home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xmcd-1.4 / libdi.d / scsipt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-10  |  77.3 KB  |  4,168 lines

  1. /*
  2.  *   libdi - CD Audio Player Device Interface Library
  3.  *
  4.  *   Copyright (C) 1995  Ti Kan
  5.  *   E-mail: ti@amb.org
  6.  *
  7.  *   This program is free software; you can redistribute it and/or modify
  8.  *   it under the terms of the GNU General Public License as published by
  9.  *   the Free Software Foundation; either version 2 of the License, or
  10.  *   (at your option) any later version.
  11.  *
  12.  *   This program is distributed in the hope that it will be useful,
  13.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *   GNU General Public License for more details.
  16.  *
  17.  *   You should have received a copy of the GNU General Public License
  18.  *   along with this program; if not, write to the Free Software
  19.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  *
  21.  */
  22. #ifndef LINT
  23. static char *_scsipt_c_ident_ = "@(#)scsipt.c    5.17 95/01/31";
  24. #endif
  25.  
  26. #include "common.d/appenv.h"
  27. #include "common.d/util.h"
  28. #include "libdi.d/libdi.h"
  29. #include "libdi.d/scsipt.h"
  30.  
  31. #ifdef DI_SCSIPT
  32.  
  33. extern appdata_t    app_data;
  34. extern FILE        *errfp;
  35.  
  36. STATIC bool_t    scsipt_run_ab(curstat_t *),
  37.         scsipt_run_sample(curstat_t *),
  38.         scsipt_run_prog(curstat_t *),
  39.         scsipt_run_repeat(curstat_t *),
  40.         scsipt_disc_ready(curstat_t *);
  41. STATIC void    scsipt_stat_poll(curstat_t *),
  42.         scsipt_insert_poll(curstat_t *);
  43.  
  44. /* Not a CD-ROM error */
  45. bool_t        scsipt_notrom_error = FALSE;
  46.  
  47. /* VU module entry jump table */
  48. vu_tbl_t    scsipt_vutbl[MAX_VENDORS];
  49.  
  50.  
  51. STATIC int    scsipt_stat_interval;        /* Status poll interval */
  52. STATIC long    scsipt_stat_id,            /* Play status poll timer id */
  53.         scsipt_insert_id,        /* Disc insert poll timer id */
  54.         scsipt_search_id;        /* FF/REW timer id */
  55. STATIC byte_t    scsipt_next_sam;        /* Next SAMPLE track */
  56. STATIC bool_t    scsipt_not_open = TRUE,        /* Device not opened yet */
  57.         scsipt_stat_polling,        /* Polling play status */
  58.         scsipt_insert_polling,        /* Polling disc insert */
  59.         scsipt_new_progshuf,        /* New program/shuffle seq */
  60.         scsipt_start_search = FALSE,    /* Start FF/REW play segment */
  61.         scsipt_idx_pause = FALSE,    /* Prev/next index pausing */
  62.         scsipt_fake_stop = FALSE;    /* Force a completion status */
  63. STATIC word32_t    scsipt_ab_start_addr,        /* A->B mode start block */
  64.         scsipt_ab_end_addr,        /* A->B mode end block */
  65.         scsipt_sav_end_addr;        /* Err recov saved end addr */
  66. STATIC msf_t    scsipt_ab_start_msf,        /* A->B mode start MSF */
  67.         scsipt_ab_end_msf,        /* A->B mode end MSF */
  68.         scsipt_sav_end_msf;        /* Err recov saved end MSF */
  69. STATIC byte_t    scsipt_dev_scsiver,        /* Device SCSI version */
  70.         scsipt_sav_end_fmt,        /* Err recov saved end fmt */
  71.         scsipt_route_left,        /* Left channel routing */
  72.         scsipt_route_right;        /* Right channel routing */
  73.  
  74. /* VU module init jump table */
  75. STATIC vuinit_tbl_t    vuinit[] = {
  76.     NULL, chin_init, hita_init, nec_init, pion_init, sony_init, tosh_init,
  77. };
  78.  
  79.  
  80. /***********************
  81.  *  internal routines  *
  82.  ***********************/
  83.  
  84.  
  85. /*
  86.  * scsipt_rdsubq
  87.  *    Send SCSI-2 Read Subchannel command to the device
  88.  *
  89.  * Args:
  90.  *    buf - Pointer to the return data buffer
  91.  *    fmt - Subchannel data format code
  92.  *        SUB_ALL        Subchannel-Q data
  93.  *        SUB_CURPOS    CD-ROM Current position data
  94.  *        SUB_CATNO    Media catalog number data
  95.  *        SUB_ISRC    Track Intl Standard Recording Code
  96.  *    subq - Whether the CD-ROM should return subchannel-Q data
  97.  *    trkno - Track number from which the ISRC data is read
  98.  *    msf - Whether to use MSF or logical block address format
  99.  *
  100.  * Return:
  101.  *    TRUE - success
  102.  *    FALSE - failure
  103.  */
  104. bool_t
  105. scsipt_rdsubq(byte_t *buf, byte_t fmt, byte_t subq, int trkno, bool_t msf)
  106. {
  107.     int    xfer_len;
  108.     bool_t    ret;
  109.  
  110.     switch (fmt) {
  111.     case SUB_ALL:
  112.         xfer_len = 48;
  113.         break;
  114.     case SUB_CURPOS:
  115.         xfer_len = 16;
  116.         break;
  117.     case SUB_CATNO:
  118.     case SUB_ISRC:
  119.         xfer_len = 24;
  120.         break;
  121.     default:
  122.         return FALSE;
  123.     }
  124.  
  125.     if (xfer_len > SZ_RDSUBQ)
  126.         xfer_len = SZ_RDSUBQ;
  127.  
  128.     ret = pthru_send(
  129.         OP_M_RDSUBQ,
  130.         (word32_t) (fmt << 16 | subq << 30),
  131.         buf,
  132.         xfer_len,
  133.         (byte_t) trkno,
  134.         xfer_len,
  135.         (byte_t) (msf << 1),
  136.         0,
  137.         READ_OP,
  138.         TRUE
  139.     );
  140.  
  141.     if (ret) {
  142.         DBGDUMP("Read Subchannel data bytes", buf, xfer_len);
  143.     }
  144.  
  145.     return (ret);
  146. }
  147.  
  148.  
  149. /*
  150.  * scsipt_modesense
  151.  *    Send SCSI Mode Sense command to the device
  152.  *
  153.  * Args:
  154.  *    buf - Pointer to the return data buffer
  155.  *    pg_ctrl - Defines the type of parameters to be returned:
  156.  *        0: Current values
  157.  *        1: Changeable values
  158.  *        2: Default values
  159.  *    pg_code - Specifies which page or pages to return:
  160.  *        PG_ERRECOV: Error recovery params page
  161.  *        PG_DISCONN: Disconnect/reconnect params page
  162.  *        PG_CDROMCTL: CD-ROM params page
  163.  *        PG_AUDIOCTL: Audio control params page
  164.  *        PG_ALL: All pages
  165.  *
  166.  * Return:
  167.  *    TRUE - success
  168.  *    FALSE - failure
  169.  */
  170. bool_t
  171. scsipt_modesense(byte_t *buf, byte_t pg_ctrl, byte_t pg_code)
  172. {
  173.     int    xfer_len;
  174.     bool_t    ret;
  175.  
  176.     switch (pg_code) {
  177.     case PG_ERRECOV:
  178.         xfer_len = 12;
  179.         break;
  180.     case PG_DISCONN:
  181.         xfer_len = 20;
  182.         break;
  183.     case PG_CDROMCTL:
  184.         xfer_len = 12;
  185.         break;
  186.     case PG_AUDIOCTL:
  187.         xfer_len = 20;
  188.         break;
  189.     case PG_ALL:
  190.         xfer_len = 52;
  191.         break;
  192.     default:
  193.         return FALSE;
  194.     }
  195.  
  196.     if (!app_data.msen_dbd)
  197.         xfer_len += 8;
  198.  
  199.     ret = pthru_send(
  200.         OP_S_MSENSE,
  201.         (word32_t) ((pg_ctrl << 6 | pg_code) << 8),
  202.         buf,
  203.         xfer_len,
  204.         0,
  205.         xfer_len,
  206.         (byte_t) (app_data.msen_dbd ? 0x08 : 0x00),
  207.         0,
  208.         READ_OP,
  209.         TRUE
  210.     );
  211.  
  212.     if (ret) {
  213.         DBGDUMP("Mode Sense data bytes", buf, xfer_len);
  214.     }
  215.  
  216.     return (ret);
  217. }
  218.  
  219.  
  220. /*
  221.  * scsipt_modesel
  222.  *    Send SCSI Mode Select command to the device
  223.  *
  224.  * Args:
  225.  *    buf - Pointer to the data buffer
  226.  *    pg_code - Specifies which page or pages to return:
  227.  *        PG_ERRECOV: Error recovery params page
  228.  *        PG_DISCONN: Disconnect/reconnect params page
  229.  *        PG_CDROMCTL: CD-ROM params page
  230.  *        PG_AUDIOCTL: Audio control params page
  231.  *        PG_ALL: All pages
  232.  *
  233.  * Return:
  234.  *    TRUE - success
  235.  *    FALSE - failure
  236.  */
  237. bool_t
  238. scsipt_modesel(byte_t *buf, byte_t pg_code)
  239. {
  240.     int    xfer_len;
  241.  
  242.     switch (pg_code) {
  243.     case PG_ERRECOV:
  244.         xfer_len = 12;
  245.         break;
  246.     case PG_DISCONN:
  247.         xfer_len = 20;
  248.         break;
  249.     case PG_CDROMCTL:
  250.         xfer_len = 12;
  251.         break;
  252.     case PG_AUDIOCTL:
  253.         xfer_len = 20;
  254.         break;
  255.     case PG_ALL:
  256.         xfer_len = 52;
  257.         break;
  258.     default:
  259.         return FALSE;
  260.     }
  261.  
  262.     if (!app_data.msen_dbd)
  263.         xfer_len += 8;
  264.  
  265.     DBGDUMP("Mode Select data bytes", buf, xfer_len);
  266.  
  267.     return (
  268.         pthru_send(
  269.             OP_S_MSELECT,
  270.             0,
  271.             buf,
  272.             xfer_len,
  273.             0,
  274.             xfer_len,
  275.             0x10,
  276.             0,
  277.             WRITE_OP,
  278.             TRUE
  279.         )
  280.     );
  281. }
  282.  
  283.  
  284. /*
  285.  * scsipt_inquiry
  286.  *    Send SCSI Inquiry command to the device
  287.  *
  288.  * Args:
  289.  *    buf - Pointer to the return data buffer
  290.  *    len - Maximum number of inquiry data bytes to transfer
  291.  *
  292.  * Return:
  293.  *    TRUE - success
  294.  *    FALSE - failure
  295.  */
  296. bool_t
  297. scsipt_inquiry(byte_t *buf, int len)
  298. {
  299.     bool_t    ret;
  300.  
  301.     ret = pthru_send(OP_S_INQUIR, 0, buf, len, 0, len, 0, 0, READ_OP, TRUE);
  302.  
  303.     if (ret) {
  304.         DBGDUMP("Inquiry data bytes", buf, len);
  305.     }
  306.  
  307.     return (ret);
  308. }
  309.  
  310.  
  311. /*
  312.  * scsipt_rdtoc
  313.  *    Send SCSI-2 Read TOC command to the device
  314.  *
  315.  * Args:
  316.  *    buf - Pointer to the return data buffer
  317.  *    msf - Whether to use MSF or logical block address data format
  318.  *    start - Starting track number for which the TOC data is returned
  319.  *
  320.  * Return:
  321.  *    TRUE - success
  322.  *    FALSE - failure
  323.  */
  324. bool_t
  325. scsipt_rdtoc(byte_t *buf, bool_t msf, int start)
  326. {
  327.     int        xfer_len;
  328.     toc_hdr_t    *thdr;
  329.     bool_t        ret;
  330.  
  331.     /* Read the TOC header first */
  332.     if (!pthru_send(OP_M_RDTOC, 0, buf, SZ_TOCHDR,
  333.             (byte_t) start, SZ_TOCHDR,
  334.             (byte_t) (msf << 1), 0, READ_OP, TRUE))
  335.         return FALSE;
  336.  
  337.     thdr = (toc_hdr_t *)(void *) buf;
  338.  
  339.     if (start == 0)
  340.         start = (int) thdr->first_trk;
  341.  
  342.     xfer_len = SZ_TOCHDR +
  343.            (((int) thdr->last_trk - start + 2) * SZ_TOCENT);
  344.  
  345.     if (xfer_len > SZ_RDTOC)
  346.         xfer_len = SZ_RDTOC;
  347.  
  348.     /* Read the appropriate number of bytes of the entire TOC */
  349.     ret = pthru_send(
  350.         OP_M_RDTOC,
  351.         0,
  352.         buf,
  353.         xfer_len,
  354.         (byte_t) start,
  355.         xfer_len,
  356.         (byte_t) (msf << 1),
  357.         0,
  358.         READ_OP,
  359.         TRUE
  360.     );
  361.  
  362.     if (ret) {
  363.         DBGDUMP("Read TOC data bytes", buf, xfer_len);
  364.     }
  365.  
  366.     return (ret);
  367. }
  368.  
  369.  
  370. /*
  371.  * scsipt_tst_unit_rdy
  372.  *    Send SCSI Test Unit Ready command to the device
  373.  *
  374.  * Args:
  375.  *    Nothing
  376.  *
  377.  * Return:
  378.  *    TRUE - success
  379.  *    FALSE - failure (drive not ready)
  380.  */
  381. bool_t
  382. scsipt_tst_unit_rdy(void)
  383. {
  384.     return (
  385.         pthru_send(
  386.             OP_S_TEST,
  387.             0,
  388.             NULL,
  389.             0,
  390.             0,
  391.             0,
  392.             0,
  393.             0,
  394.             READ_OP,
  395.             app_data.debug
  396.         )
  397.     );
  398. }
  399.  
  400.  
  401. /*
  402.  * scsipt_playmsf
  403.  *    Send SCSI-2 Play Audio MSF command to the device
  404.  *
  405.  * Args:
  406.  *    start - Pointer to the starting position MSF data
  407.  *    end - Pointer to the ending position MSF data
  408.  *
  409.  * Return:
  410.  *    TRUE - success
  411.  *    FALSE - failure
  412.  */
  413. bool_t
  414. scsipt_playmsf(msf_t *start, msf_t *end)
  415. {
  416.     word32_t    *addr = (word32_t *)(void *) start;
  417.     word16_t    *len = (word16_t *)(void *) &end->sec;
  418.     byte_t        *rsvd = (byte_t *) &end->min;
  419.  
  420.     if (!app_data.playmsf_supp)
  421.         return FALSE;
  422.  
  423.     start->res = end->res = 0;
  424.  
  425.     return (
  426.         pthru_send(
  427.             OP_M_PLAYMSF,
  428.             bswap32(*addr),
  429.             NULL,
  430.             0,
  431.             *rsvd,
  432.             (word32_t) bswap16(*len),
  433.             0,
  434.             0,
  435.             READ_OP,
  436.             TRUE
  437.         )
  438.     );
  439. }
  440.  
  441.  
  442. /*
  443.  * scsipt_play10
  444.  *    Send SCSI-2 Play Audio (10) command to the device
  445.  *
  446.  * Args:
  447.  *    start - The starting logical block address
  448.  *    len - The number of logical blocks to play (max=0xffff)
  449.  *
  450.  * Return:
  451.  *    TRUE - success
  452.  *    FALSE - failure
  453.  */
  454. bool_t
  455. scsipt_play10(word32_t start, word32_t len)
  456. {
  457.     if (!app_data.play10_supp || len > 0xffff)
  458.         return FALSE;
  459.  
  460.     return (
  461.         pthru_send(
  462.             OP_M_PLAY,
  463.             start,
  464.             NULL,
  465.             0,
  466.             0,
  467.             len,
  468.             0,
  469.             0,
  470.             READ_OP,
  471.             TRUE
  472.         )
  473.     );
  474. }
  475.  
  476.  
  477. /*
  478.  * scsipt_play12
  479.  *    Send SCSI-2 Play Audio (12) command to the device
  480.  *
  481.  * Args:
  482.  *    start - The starting logical block address
  483.  *    len - The number of logical blocks to play
  484.  *
  485.  * Return:
  486.  *    TRUE - success
  487.  *    FALSE - failure
  488.  */
  489. bool_t
  490. scsipt_play12(word32_t start, word32_t len)
  491. {
  492.     if (!app_data.play12_supp)
  493.         return FALSE;
  494.  
  495.     return (
  496.         pthru_send(
  497.             OP_L_PLAY,
  498.             start,
  499.             NULL,
  500.             0,
  501.             0,
  502.             len,
  503.             0,
  504.             0,
  505.             READ_OP,
  506.             TRUE
  507.         )
  508.     );
  509. }
  510.  
  511.  
  512. /*
  513.  * scsipt_prev_allow
  514.  *    Send SCSI Prevent/Allow Medium Removal command to the device
  515.  *
  516.  * Args:
  517.  *    prevent - Whether to prevent or allow medium removal
  518.  *
  519.  * Return:
  520.  *    TRUE - success
  521.  *    FALSE - failure
  522.  */
  523. bool_t
  524. scsipt_prev_allow(bool_t prevent)
  525. {
  526.     if (!app_data.caddylock_supp)
  527.         return FALSE;
  528.  
  529.     return (
  530.         pthru_send(
  531.             OP_S_PREVENT,
  532.             0,
  533.             NULL,
  534.             0,
  535.             0,
  536.             prevent,
  537.             0,
  538.             0,
  539.             READ_OP,
  540.             TRUE
  541.         )
  542.     );
  543. }
  544.  
  545.  
  546. /*
  547.  * scsipt_start_stop
  548.  *    Send SCSI Start/Stop Unit command to the device
  549.  *
  550.  * Args:
  551.  *    start - Whether to start unit or stop unit
  552.  *    loej - Whether caddy load/eject operation should be performed
  553.  *
  554.  * Return:
  555.  *    TRUE - success
  556.  *    FALSE - failure
  557.  */
  558. bool_t
  559. scsipt_start_stop(bool_t start, bool_t loej)
  560. {
  561.     byte_t    ctl;
  562.  
  563.     if (start)
  564.         ctl = 0x01;
  565.     else
  566.         ctl = 0x00;
  567.  
  568.     if (loej)
  569.         ctl |= 0x02;
  570.  
  571.     return (
  572.         pthru_send(
  573.             OP_S_START,
  574.             0,
  575.             NULL,
  576.             0,
  577.             0,
  578.             ctl,
  579.             0x1,
  580.             0,
  581.             READ_OP,
  582.             TRUE
  583.         )
  584.     );
  585. }
  586.  
  587.  
  588. /*
  589.  * scsipt_pause_resume
  590.  *    Send SCSI-2 Pause/Resume command to the device
  591.  *
  592.  * Args:
  593.  *    resume - Whether to resume or pause
  594.  *
  595.  * Return:
  596.  *    TRUE - success
  597.  *    FALSE - failure
  598.  */
  599. bool_t
  600. scsipt_pause_resume(bool_t resume)
  601. {
  602.     if (!app_data.pause_supp)
  603.         return FALSE;
  604.  
  605.     return (
  606.         pthru_send(
  607.             OP_M_PAUSE,
  608.             0,
  609.             NULL,
  610.             0,
  611.             0,
  612.             resume,
  613.             0,
  614.             0,
  615.             READ_OP,
  616.             TRUE
  617.         )
  618.     );
  619. }
  620.  
  621.  
  622. /*
  623.  * scsipt_play_trkidx
  624.  *    Send SCSI-2 Play Audio Track/Index command to the device
  625.  *
  626.  * Args:
  627.  *    start_trk - Starting track number
  628.  *    start_idx - Starting index number
  629.  *    end_trk - Ending track number
  630.  *    end_idx - Ending index number
  631.  *
  632.  * Return:
  633.  *    TRUE - success
  634.  *    FALSE - failure
  635.  */
  636. bool_t
  637. scsipt_play_trkidx(int start_trk, int start_idx, int end_trk, int end_idx)
  638. {
  639.     if (!app_data.playti_supp)
  640.         return FALSE;
  641.  
  642.     return (
  643.         pthru_send(
  644.             OP_M_PLAYTI,
  645.             (start_trk << 8) | start_idx,
  646.             NULL,
  647.             0,
  648.             0,
  649.             (end_trk << 8) | end_idx,
  650.             0,
  651.             0,
  652.             READ_OP,
  653.             TRUE
  654.         )
  655.     );
  656. }
  657.  
  658.  
  659. /*
  660.  * scsipt_do_playaudio
  661.  *    General top-level play audio function
  662.  *
  663.  * Args:
  664.  *    addr_fmt - The address formats specified:
  665.  *        ADDR_BLK: logical block address
  666.  *        ADDR_MSF: MSF address
  667.  *        ADDR_TRKIDX: Track/index numbers
  668.  *        ADDR_OPTEND: Ending address can be ignored
  669.  *    start_addr - Starting logical block address
  670.  *    end_addr - Ending logical block address
  671.  *    start_msf - Pointer to start address MSF data
  672.  *    end_msf - Pointer to end address MSF data
  673.  *    trk - Starting track number
  674.  *    idx - Starting index number
  675.  *
  676.  * Return:
  677.  *    TRUE - success
  678.  *    FALSE - failure
  679.  */
  680. STATIC bool_t
  681. scsipt_do_playaudio(
  682.     byte_t        addr_fmt,
  683.     word32_t    start_addr,
  684.     word32_t    end_addr,
  685.     msf_t        *start_msf,
  686.     msf_t        *end_msf,
  687.     byte_t        trk,
  688.     byte_t        idx
  689. )
  690. {
  691.     msf_t        emsf,
  692.             *emsfp = NULL;
  693.     bool_t        ret = FALSE;
  694.  
  695.  
  696.     /* Fix addresses: Some CD-ROM drives will only allow playing to
  697.      * the last frame minus 1.
  698.      */
  699.     if (addr_fmt & ADDR_MSF && end_msf != NULL) {
  700.         emsf = *end_msf;    /* Structure copy */
  701.         emsfp = &emsf;
  702.  
  703.         if (emsfp->frame > 0)
  704.             emsfp->frame--;
  705.         else {
  706.             emsfp->frame = FRAME_PER_SEC - 1;
  707.             if (emsfp->sec > 0)
  708.                 emsfp->sec--;
  709.             else {
  710.                 emsfp->sec = 59;
  711.                 if (emsfp->min > 0)
  712.                     emsfp->min--;
  713.             }
  714.         }
  715.  
  716.         emsfp->res = start_msf->res = 0;
  717.  
  718.         /* Save end address for error recovery */
  719.         scsipt_sav_end_msf = *end_msf;
  720.     }
  721.     if (addr_fmt & ADDR_BLK) {
  722.         if (end_addr != 0)
  723.             end_addr--;
  724.  
  725.         /* Save end address for error recovery */
  726.         scsipt_sav_end_addr = end_addr;
  727.     }
  728.  
  729.     /* Save end address format for error recovery */
  730.     scsipt_sav_end_fmt = addr_fmt;
  731.  
  732.     if (scsipt_vutbl[app_data.vendor_code].playaudio != NULL) {
  733.         ret = scsipt_vutbl[app_data.vendor_code].playaudio(
  734.             addr_fmt,
  735.             start_addr, end_addr,
  736.             start_msf, emsfp,
  737.             trk, idx
  738.         );
  739.     }
  740.  
  741.     /* If the device does not claim SCSI-2 compliance, and the
  742.      * device-specific configuration is not SCSI-2, then don't
  743.      * attempt to deliver SCSI-2 commands to the device.
  744.      */
  745.     if (!ret && app_data.vendor_code != VENDOR_SCSI2 &&
  746.         scsipt_dev_scsiver < 2)
  747.         return FALSE;
  748.     
  749.     if (!ret && (addr_fmt & ADDR_MSF) && app_data.playmsf_supp)
  750.         ret = scsipt_playmsf(start_msf, emsfp);
  751.     
  752.     if (!ret && (addr_fmt & ADDR_BLK) && app_data.play12_supp)
  753.         ret = scsipt_play12(start_addr, end_addr - start_addr);
  754.     
  755.     if (!ret && (addr_fmt & ADDR_BLK) && app_data.play10_supp)
  756.         ret = scsipt_play10(start_addr, end_addr - start_addr);
  757.  
  758.     if (!ret && (addr_fmt & ADDR_TRKIDX) && app_data.playti_supp)
  759.         ret = scsipt_play_trkidx(trk, idx, trk, idx);
  760.  
  761.     return (ret);
  762. }
  763.  
  764.  
  765. /*
  766.  * scsipt_do_pause_resume
  767.  *    General top-level pause/resume function
  768.  *
  769.  * Args:
  770.  *    resume - Whether to resume or pause
  771.  *
  772.  * Return:
  773.  *    TRUE - success
  774.  *    FALSE - failure
  775.  */
  776. STATIC bool_t
  777. scsipt_do_pause_resume(bool_t resume)
  778. {
  779.     bool_t    ret = FALSE;
  780.  
  781.     if (scsipt_vutbl[app_data.vendor_code].pause_resume != NULL)
  782.         ret = scsipt_vutbl[app_data.vendor_code].pause_resume(resume);
  783.  
  784.     /* If the device does not claim SCSI-2 compliance, and the
  785.      * device-specific configuration is not SCSI-2, then don't
  786.      * attempt to deliver SCSI-2 commands to the device.
  787.      */
  788.     if (!ret && app_data.vendor_code != VENDOR_SCSI2 &&
  789.         scsipt_dev_scsiver < 2)
  790.         return FALSE;
  791.  
  792.     if (!ret && app_data.pause_supp)
  793.         ret = scsipt_pause_resume(resume);
  794.  
  795.     return (ret);
  796. }
  797.  
  798.  
  799. /*
  800.  * scsipt_do_start_stop
  801.  *    General top-level start/stop function
  802.  *
  803.  * Args:
  804.  *    start - Whether to start unit or stop unit
  805.  *    loej - Whether caddy load/eject operation should be performed
  806.  *
  807.  * Return:
  808.  *    TRUE - success
  809.  *    FALSE - failure
  810.  */
  811. STATIC bool_t
  812. scsipt_do_start_stop(bool_t start, bool_t loej)
  813. {
  814.     bool_t    ret = FALSE;
  815.  
  816.     if (!app_data.load_supp && start && loej)
  817.         return FALSE;
  818.  
  819.     if (!app_data.eject_supp)
  820.         loej = 0;
  821.  
  822.     if (!start && loej &&
  823.         scsipt_vutbl[app_data.vendor_code].eject != NULL)
  824.         ret = scsipt_vutbl[app_data.vendor_code].eject();
  825.  
  826.     if (!ret && scsipt_vutbl[app_data.vendor_code].start_stop != NULL)
  827.         ret = scsipt_vutbl[app_data.vendor_code].start_stop(
  828.             start, loej
  829.         );
  830.  
  831. #ifdef SOL2_VOLMGT
  832.     /* Sun Hack: Under Solaris 2.x with the Volume Manager
  833.      * we need to use a special SunOS ioctl to eject the CD.
  834.      */
  835.     if (app_data.sol2_volmgt && !start && loej)
  836.         ret = sol2_volmgt_eject();
  837. #endif
  838.  
  839.     if (!ret)
  840.         ret = scsipt_start_stop(start, loej);
  841.  
  842.     return (ret);
  843. }
  844.  
  845.  
  846. /*
  847.  * scsipt_get_playstatus
  848.  *    Obtain and update current playback status information
  849.  *
  850.  * Args:
  851.  *    s - Pointer to the curstat_t structure
  852.  *
  853.  * Return:
  854.  *    TRUE - Audio playback is in progress
  855.  *    FALSE - Audio playback stopped or command failure
  856.  */
  857. STATIC bool_t
  858. scsipt_get_playstatus(curstat_t *s)
  859. {
  860.     msf_t        recov_start_msf;
  861.     word32_t    recov_start_addr;
  862.     byte_t        buf[SZ_RDSUBQ],
  863.             audio_status,
  864.             *cp;
  865.     bool_t        done,
  866.             ret = FALSE;
  867.     subq_hdr_t    *h;
  868.     subq_01_t    *p;
  869.     static int    errcnt = 0;
  870.     static word32_t    errblk = 0;
  871.     static bool_t    in_scsipt_get_playstatus = FALSE;
  872.  
  873.  
  874.     /* Lock this routine from multiple entry */
  875.     if (in_scsipt_get_playstatus)
  876.         return TRUE;
  877.  
  878.     in_scsipt_get_playstatus = TRUE;
  879.  
  880.     if (scsipt_vutbl[app_data.vendor_code].get_playstatus != NULL) {
  881.         ret = scsipt_vutbl[app_data.vendor_code].get_playstatus(
  882.             s, &audio_status
  883.         );
  884.     }
  885.  
  886.     /* If the device does not claim SCSI-2 compliance, and the
  887.      * device-specific configuration is not SCSI-2, then don't
  888.      * attempt to deliver SCSI-2 commands to the device.
  889.      */
  890.     if (!ret && app_data.vendor_code != VENDOR_SCSI2 &&
  891.         scsipt_dev_scsiver < 2) {
  892.         in_scsipt_get_playstatus = FALSE;
  893.         return FALSE;
  894.     }
  895.  
  896.     if (!ret) {
  897.         memset(buf, 0, sizeof(buf));
  898.  
  899.         if (!scsipt_rdsubq(buf, (byte_t)
  900.                  (app_data.curpos_fmt ? SUB_CURPOS : SUB_ALL),
  901.                  1, 0, TRUE)) {
  902.             /* Check to see if the disc had been manually ejected */
  903.             if (!scsipt_disc_ready(s)) {
  904.                 scsipt_sav_end_addr = 0;
  905.                 scsipt_sav_end_msf.min = 0;
  906.                 scsipt_sav_end_msf.sec = 0;
  907.                 scsipt_sav_end_msf.frame = 0;
  908.                 scsipt_sav_end_fmt = 0;
  909.                 errcnt = 0;
  910.                 errblk = 0;
  911.  
  912.                 in_scsipt_get_playstatus = FALSE;
  913.                 return FALSE;
  914.             }
  915.  
  916.             /* The read subchannel command failed for some
  917.              * unknown reason.  Just return success and
  918.              * hope the next poll succeeds.  We don't want
  919.              * to return FALSE here because that would stop
  920.              * the poll.
  921.              */
  922.             in_scsipt_get_playstatus = FALSE;
  923.             return TRUE;
  924.         }
  925.  
  926.         h = (subq_hdr_t *)(void *) buf;
  927.  
  928.         audio_status = h->audio_status;
  929.  
  930.         /* Check the subchannel data */
  931.         cp = (byte_t *) h + sizeof(subq_hdr_t);
  932.         switch (*cp) {
  933.         case SUB_ALL:
  934.         case SUB_CURPOS:
  935.             p = (subq_01_t *)(void *) cp;
  936.  
  937.             if (p->trkno != s->cur_trk) {
  938.                 s->cur_trk = p->trkno;
  939.                 dpy_track(s);
  940.             }
  941.  
  942.             if (p->idxno != s->cur_idx) {
  943.                 s->cur_idx = p->idxno;
  944.                 s->sav_iaddr = s->cur_tot_addr;
  945.                 dpy_index(s);
  946.             }
  947.  
  948.             s->cur_tot_min = p->abs_addr.msf.min;
  949.             s->cur_tot_sec = p->abs_addr.msf.sec;
  950.             s->cur_tot_frame = p->abs_addr.msf.frame;
  951.             msftoblk(
  952.                 s->cur_tot_min,
  953.                 s->cur_tot_sec,
  954.                 s->cur_tot_frame,
  955.                 &s->cur_tot_addr,
  956.                 MSF_OFFSET(s)
  957.             );
  958.  
  959.             s->cur_trk_min = p->rel_addr.msf.min;
  960.             s->cur_trk_sec = p->rel_addr.msf.sec;
  961.             s->cur_trk_frame = p->rel_addr.msf.frame;
  962.             msftoblk(
  963.                 s->cur_trk_min,
  964.                 s->cur_trk_sec,
  965.                 s->cur_trk_frame,
  966.                 &s->cur_trk_addr,
  967.                 0
  968.             );
  969.  
  970.             break;
  971.         default:
  972.             /* Something is wrong with the data */
  973.             break;
  974.         }
  975.     }
  976.  
  977.     /* Update time display */
  978.     dpy_time(s, FALSE);
  979.  
  980.  
  981.     /* Hack: to work around the fact that some CD-ROM drives
  982.      * return AUDIO_PAUSED status after issuing a Stop Unit command.
  983.      * Just treat the status as completed if we get a paused status
  984.      * and we don't expect the drive to be paused.
  985.      */
  986.     if (audio_status == AUDIO_PAUSED && s->mode != M_PAUSE &&
  987.         !scsipt_idx_pause)
  988.         audio_status = AUDIO_COMPLETED;
  989.  
  990.     /* Force completion status */
  991.     if (scsipt_fake_stop) {
  992.         scsipt_fake_stop = FALSE;
  993.         audio_status = AUDIO_COMPLETED;
  994.     }
  995.  
  996.     /* Deal with playback status */
  997.     switch (audio_status) {
  998.     case AUDIO_PLAYING:
  999.     case AUDIO_PAUSED:
  1000.         done = FALSE;
  1001.  
  1002.         /* If we haven't encountered an error for a while, then
  1003.          * clear the error count.
  1004.          */
  1005.         if (errcnt > 0 && (s->cur_tot_addr - errblk) > ERR_CLRTHRESH)
  1006.             errcnt = 0;
  1007.         break;
  1008.  
  1009.     case AUDIO_FAILED:
  1010.         /* Check to see if the disc had been manually ejected */
  1011.         if (!scsipt_disc_ready(s)) {
  1012.             scsipt_sav_end_addr = 0;
  1013.             scsipt_sav_end_msf.min = 0;
  1014.             scsipt_sav_end_msf.sec = 0;
  1015.             scsipt_sav_end_msf.frame = 0;
  1016.             scsipt_sav_end_fmt = 0;
  1017.             errcnt = 0;
  1018.             errblk = 0;
  1019.  
  1020.             in_scsipt_get_playstatus = FALSE;
  1021.             return FALSE;
  1022.         }
  1023.  
  1024.         /* Audio playback stopped due to a disc error.  We will
  1025.          * try to restart the playback by skipping a few frames
  1026.          * and continuing.  This will cause a glitch in the sound
  1027.          * but is better than just stopping.
  1028.          */
  1029.         done = FALSE;
  1030.  
  1031.         /* Check for max errors limit */
  1032.         if (++errcnt > MAX_RECOVERR) {
  1033.             done = TRUE;
  1034.             fprintf(errfp, "CD audio: %s\n", app_data.str_maxerr);
  1035.         }
  1036.         errblk = s->cur_tot_addr;
  1037.  
  1038.         if (!done && (scsipt_sav_end_fmt & ADDR_MSF)) {
  1039.             if ((int) s->cur_tot_frame <
  1040.                 (FRAME_PER_SEC - ERR_SKIPBLKS)) {
  1041.                 recov_start_msf.min = s->cur_tot_min;
  1042.                 recov_start_msf.sec = s->cur_tot_sec;
  1043.                 recov_start_msf.frame =
  1044.                     s->cur_tot_frame + ERR_SKIPBLKS;
  1045.             }
  1046.             else if ((int) s->cur_tot_sec < 59) {
  1047.                 recov_start_msf.min = s->cur_tot_min;
  1048.                 recov_start_msf.sec = s->cur_tot_sec + 1;
  1049.                 recov_start_msf.frame = ERR_SKIPBLKS -
  1050.                     (FRAME_PER_SEC - s->cur_tot_frame);
  1051.             }
  1052.             else {
  1053.                 recov_start_msf.min = s->cur_tot_min + 1;
  1054.                 recov_start_msf.sec = 0;
  1055.                 recov_start_msf.frame = ERR_SKIPBLKS -
  1056.                     (FRAME_PER_SEC - s->cur_tot_frame);
  1057.             }
  1058.  
  1059.             /* Check to see if we have skipped past
  1060.              * the end.
  1061.              */
  1062.             if (recov_start_msf.min > scsipt_sav_end_msf.min)
  1063.                 done = TRUE;
  1064.             else if (recov_start_msf.min ==
  1065.                  scsipt_sav_end_msf.min) {
  1066.                 if (recov_start_msf.sec >
  1067.                     scsipt_sav_end_msf.sec)
  1068.                     done = TRUE;
  1069.                 else if ((recov_start_msf.sec ==
  1070.                       scsipt_sav_end_msf.sec) &&
  1071.                      (recov_start_msf.frame >
  1072.                       scsipt_sav_end_msf.frame)) {
  1073.                     done = TRUE;
  1074.                 }
  1075.             }
  1076.         }
  1077.         else {
  1078.             recov_start_msf.min = 0;
  1079.             recov_start_msf.sec = 0;
  1080.             recov_start_msf.frame = 0;
  1081.         }
  1082.  
  1083.         if (!done && (scsipt_sav_end_fmt & ADDR_BLK)) {
  1084.             recov_start_addr = s->cur_tot_addr + ERR_SKIPBLKS;
  1085.  
  1086.             /* Check to see if we have skipped past
  1087.              * the end.
  1088.              */
  1089.             if (recov_start_addr >= scsipt_sav_end_addr)
  1090.                 done = TRUE;
  1091.         }
  1092.         else
  1093.             recov_start_addr = 0;
  1094.  
  1095.  
  1096.         /* Restart playback */
  1097.         if (!done) {
  1098.             fprintf(errfp, "CD audio: %s\n",
  1099.                 app_data.str_recoverr);
  1100.  
  1101.             scsipt_do_playaudio(
  1102.                 scsipt_sav_end_fmt,
  1103.                 recov_start_addr, scsipt_sav_end_addr,
  1104.                 &recov_start_msf, &scsipt_sav_end_msf,
  1105.                 0, 0
  1106.             );
  1107.  
  1108.             in_scsipt_get_playstatus = FALSE;
  1109.             return TRUE;
  1110.         }
  1111.  
  1112.         /*FALLTHROUGH*/
  1113.     case AUDIO_COMPLETED:
  1114.     case AUDIO_NOSTATUS:
  1115.     case AUDIO_NOTVALID:
  1116.         done = TRUE;
  1117.  
  1118.         switch (s->mode) {
  1119.         case M_SAMPLE:
  1120.             done = !scsipt_run_sample(s);
  1121.             break;
  1122.  
  1123.         case M_AB:
  1124.             done = !scsipt_run_ab(s);
  1125.             break;
  1126.  
  1127.         case M_PLAY:
  1128.         case M_PAUSE:
  1129.             s->cur_trk_addr = 0;
  1130.             s->cur_trk_min = s->cur_trk_sec = s->cur_trk_frame = 0;
  1131.  
  1132.             if (s->shuffle || s->program)
  1133.                 done = !scsipt_run_prog(s);
  1134.  
  1135.             if (s->repeat)
  1136.                 done = !scsipt_run_repeat(s);
  1137.  
  1138.             break;
  1139.         }
  1140.  
  1141.         break;
  1142.  
  1143.     default:
  1144.         /* Something is wrong with the data. */
  1145.         done = FALSE;
  1146.     }
  1147.  
  1148.     if (done) {
  1149.         /* Reset states */
  1150.         reset_curstat(s, FALSE);
  1151.         s->mode = M_STOP;
  1152.         scsipt_sav_end_addr = 0;
  1153.         scsipt_sav_end_msf.min = scsipt_sav_end_msf.sec =
  1154.             scsipt_sav_end_msf.frame = 0;
  1155.         scsipt_sav_end_fmt = 0;
  1156.         errcnt = 0;
  1157.         errblk = 0;
  1158.         dpy_all(s);
  1159.  
  1160.         if (app_data.done_eject) {
  1161.             /* Eject the disc */
  1162.             scsipt_load_eject(s);
  1163.         }
  1164.         else {
  1165.             /* Spin down the disc */
  1166.             scsipt_do_start_stop(FALSE, FALSE);
  1167.         }
  1168.  
  1169.         in_scsipt_get_playstatus = FALSE;
  1170.         return FALSE;
  1171.     }
  1172.  
  1173.     in_scsipt_get_playstatus = FALSE;
  1174.     return TRUE;
  1175. }
  1176.  
  1177.  
  1178. /*
  1179.  * scsipt_cfg_vol
  1180.  *    Audio volume control function
  1181.  *
  1182.  * Args:
  1183.  *    vol - Logical volume value to set to
  1184.  *    s - Pointer to the curstat_t structure
  1185.  *    query - If TRUE, query current volume only
  1186.  *    warp - Whether to set the volume and balance control slider
  1187.  *        thumbs to the appropriate position.
  1188.  *        Bits: WARP_VOL WARP_BAL
  1189.  *
  1190.  * Return:
  1191.  *    The current logical volume value, or -1 on failure.
  1192.  */
  1193. STATIC int
  1194. scsipt_cfg_vol(int vol, curstat_t *s, bool_t query, byte_t warp)
  1195. {
  1196.     int            vol1,
  1197.                 vol2;
  1198.     mode_sense_data_t    *ms_data;
  1199.     blk_desc_t        *bdesc;
  1200.     audio_pg_t        *audiopg;
  1201.     bool_t            ret = FALSE;
  1202.     byte_t            buf[SZ_MSENSE];
  1203.     static bool_t        muted = FALSE;
  1204.  
  1205.  
  1206.     if (scsipt_vutbl[app_data.vendor_code].volume != NULL) {
  1207.         vol = scsipt_vutbl[app_data.vendor_code].volume(vol, s, query);
  1208.  
  1209.         if (query && vol >= 0) {
  1210.             if (warp & WARP_VOL)
  1211.                 set_vol_slider(vol);
  1212.  
  1213.             if (warp & WARP_BAL)
  1214.                 set_bal_slider(
  1215.                     (int) (s->level_right - s->level_left) / 2
  1216.                 );
  1217.         }
  1218.  
  1219.         return (vol);
  1220.     }
  1221.  
  1222.     if (scsipt_vutbl[app_data.vendor_code].mute != NULL) {
  1223.         if (!query) {
  1224.             if (vol < (int) s->level)
  1225.                 vol = 0;
  1226.             else if (vol > (int) s->level ||
  1227.                  (vol != 0 && vol != 100))
  1228.                 vol = 100;
  1229.  
  1230.             ret = scsipt_vutbl[app_data.vendor_code].mute(
  1231.                 (bool_t) (vol == 0)
  1232.             );
  1233.             if (ret)
  1234.                 muted = (vol == 0);
  1235.         }
  1236.  
  1237.         vol = muted ? 0 : MAX_VOL;
  1238.  
  1239.         if (warp & WARP_VOL)
  1240.             set_vol_slider(vol);
  1241.  
  1242.         if (warp & WARP_BAL)
  1243.             set_bal_slider(
  1244.                 (int) (s->level_right - s->level_left) / 2
  1245.             );
  1246.  
  1247.         return (vol);
  1248.     }
  1249.  
  1250.     if (!app_data.mselvol_supp)
  1251.         return 0;
  1252.  
  1253.     memset(buf, 0, SZ_MSENSE);
  1254.  
  1255.     if (!scsipt_modesense(buf, 0, PG_AUDIOCTL))
  1256.         return -1;
  1257.  
  1258.     ms_data = (mode_sense_data_t *)(void *) buf;
  1259.     bdesc = (blk_desc_t *)(void *) ms_data->data;
  1260.     audiopg = (audio_pg_t *)(void *)
  1261.         &ms_data->data[ms_data->bdescr_len];
  1262.  
  1263.     if (audiopg->pg_code == PG_AUDIOCTL) {
  1264.         if (query) {
  1265.             vol1 = untaper_vol(unscale_vol((int) audiopg->p0_vol));
  1266.             vol2 = untaper_vol(unscale_vol((int) audiopg->p1_vol));
  1267.             scsipt_route_left = (byte_t) audiopg->p0_ch_ctrl;
  1268.             scsipt_route_right = (byte_t) audiopg->p1_ch_ctrl;
  1269.  
  1270.             if (vol1 == vol2) {
  1271.                 s->level_left = s->level_right = 100;
  1272.                 vol = vol1;
  1273.             }
  1274.             else if (vol1 > vol2) {
  1275.                 s->level_left = 100;
  1276.                 s->level_right = (byte_t) ((vol2 * 100) / vol1);
  1277.                 vol = vol1;
  1278.             }
  1279.             else {
  1280.                 s->level_left = (byte_t) ((vol1 * 100) / vol2);
  1281.                 s->level_right = 100;
  1282.                 vol = vol2;
  1283.             }
  1284.  
  1285.             if (warp & WARP_VOL)
  1286.                 set_vol_slider(vol);
  1287.  
  1288.             if (warp & WARP_BAL)
  1289.                 set_bal_slider(
  1290.                     (int) (s->level_right - s->level_left) / 2
  1291.                 );
  1292.  
  1293.             return (vol);
  1294.         }
  1295.         else {
  1296.             ms_data->data_len = 0;
  1297.             if (ms_data->bdescr_len > 0)
  1298.                 bdesc->num_blks = 0;
  1299.  
  1300.             audiopg->p0_vol = scale_vol(
  1301.                 taper_vol(vol * (int) s->level_left / 100)
  1302.             );
  1303.             audiopg->p1_vol = scale_vol(
  1304.                 taper_vol(vol * (int) s->level_right / 100)
  1305.             );
  1306.  
  1307.             audiopg->p0_ch_ctrl = scsipt_route_left;
  1308.             audiopg->p1_ch_ctrl = scsipt_route_right;
  1309.  
  1310.             audiopg->sotc = 0;
  1311.             audiopg->immed = 1;
  1312.  
  1313.             if (scsipt_modesel(buf, PG_AUDIOCTL)) {
  1314.                 /* Success */
  1315.                 return (vol);
  1316.             }
  1317.             else if (audiopg->p0_vol != audiopg->p1_vol) {
  1318.                 /* Set the balance to the center
  1319.                  * and retry.
  1320.                  */
  1321.                 audiopg->p0_vol = audiopg->p1_vol =
  1322.                     scale_vol(taper_vol(vol));
  1323.  
  1324.                 if (scsipt_modesel(buf, PG_AUDIOCTL)) {
  1325.                     /* Success: Warp balance control */
  1326.                     s->level_left = s->level_right = 100;
  1327.                     set_bal_slider(0);
  1328.  
  1329.                     return (vol);
  1330.                 }
  1331.  
  1332.                 /* Still failed: just drop through */
  1333.             }
  1334.         }
  1335.     }
  1336.  
  1337.     return -1;
  1338. }
  1339.  
  1340.  
  1341. /*
  1342.  * scsipt_vendor_model
  1343.  *    Query and update CD-ROM vendor/model/revision information
  1344.  *
  1345.  * Args:
  1346.  *    s - Pointer to the curstat_t structure
  1347.  *
  1348.  * Return:
  1349.  *    Nothing.
  1350.  */
  1351. STATIC void
  1352. scsipt_vendor_model(curstat_t *s)
  1353. {
  1354.     inquiry_data_t    inq;
  1355.     char        errstr[ERR_BUF_SZ];
  1356.  
  1357.     if (scsipt_inquiry((byte_t *) &inq, sizeof(inq))) {
  1358.         strncpy(s->vendor, (char *) inq.vendor, 8);
  1359.         s->vendor[8] = '\0';
  1360.  
  1361.         strncpy(s->prod, (char *) inq.prod, 16);
  1362.         s->prod[16] = '\0';
  1363.  
  1364.         strncpy(s->revnum, (char *) inq.revnum, 4);
  1365.         s->revnum[4] = '\0';
  1366.  
  1367. #ifndef OEM_CDROM
  1368.         /* Check for errors.
  1369.          * Note: Some OEM drives identify themselves
  1370.          * as a hard disk instead of a CD-ROM drive
  1371.          * (such as the Toshiba CD-ROM XM revision 1971
  1372.          * OEMed by SGI).  In order to use those units
  1373.          * this file must be compiled with -DOEM_CDROM.
  1374.          */
  1375.         if (inq.type != DEV_ROM || !inq.rmb) {
  1376.             /* Not a CD-ROM device */
  1377.             scsipt_notrom_error = TRUE;
  1378.             sprintf(errstr, app_data.str_notrom, app_data.device);
  1379.             cd_fatal_popup(app_data.str_fatal, errstr);
  1380.             return;
  1381.         }
  1382. #endif
  1383.  
  1384.         /* Check for unsupported drives */
  1385.         scsipt_dev_scsiver = (byte_t) (inq.ver & 0x07);
  1386.         if (scsipt_dev_scsiver < 2 &&
  1387.             app_data.vendor_code == VENDOR_SCSI2) {
  1388.             /* Not SCSI-2 or later */
  1389.             sprintf(errstr, app_data.str_notscsi2, app_data.device);
  1390.             cd_warning_popup(app_data.str_warning, errstr);
  1391.         }
  1392.     }
  1393. }
  1394.  
  1395.  
  1396. /*
  1397.  * scsipt_get_toc
  1398.  *    Query and update the CD Table Of Contents
  1399.  *
  1400.  * Args:
  1401.  *    s - Pointer to the curstat_t structure
  1402.  *
  1403.  * Return:
  1404.  *    TRUE - success
  1405.  *    FALSE - failure
  1406.  */
  1407. STATIC bool_t
  1408. scsipt_get_toc(curstat_t *s)
  1409. {
  1410.     int            i;
  1411.     byte_t            buf[SZ_RDTOC],
  1412.                 *cp,
  1413.                 *toc_end;
  1414.     bool_t            ret = FALSE;
  1415.     toc_hdr_t        *h;
  1416.     toc_trk_descr_t        *p;
  1417.  
  1418.  
  1419.     if (scsipt_vutbl[app_data.vendor_code].get_toc != NULL)
  1420.         ret = scsipt_vutbl[app_data.vendor_code].get_toc(s);
  1421.  
  1422.     if (ret)
  1423.         return TRUE;
  1424.  
  1425.     /* If the device does not claim SCSI-2 compliance, and the
  1426.      * device-specific configuration is not SCSI-2, then don't
  1427.      * attempt to deliver SCSI-2 commands to the device.
  1428.      */
  1429.     if (!ret && app_data.vendor_code != VENDOR_SCSI2 &&
  1430.         scsipt_dev_scsiver < 2)
  1431.         return FALSE;
  1432.  
  1433.     memset(buf, 0, sizeof(buf));
  1434.  
  1435.     if (!scsipt_rdtoc(buf, TRUE, 0))
  1436.         return FALSE;
  1437.  
  1438.     /* Fill curstat structure with TOC data */
  1439.     h = (toc_hdr_t *)(void *) buf;
  1440.     toc_end = (byte_t *) h + bswap16(h->data_len) + 2;
  1441.  
  1442.     s->first_trk = h->first_trk;
  1443.     s->last_trk = h->last_trk;
  1444.  
  1445.     cp = (byte_t *) h + sizeof(toc_hdr_t);
  1446.  
  1447.     for (i = 0; cp < toc_end && i < MAXTRACK; i++) {
  1448.         p = (toc_trk_descr_t *)(void *) cp;
  1449.  
  1450.         /* Hack: Work around firmware problem on some drives */
  1451.         if (i > 0 && s->trkinfo[i-1].trkno == s->last_trk &&
  1452.             p->trkno != LEAD_OUT_TRACK) {
  1453.             memset(buf, 0, sizeof(buf));
  1454.  
  1455.             if (!scsipt_rdtoc(buf, TRUE, (int) s->last_trk))
  1456.                 return FALSE;
  1457.  
  1458.             cp = (byte_t *) h + sizeof(toc_hdr_t) +
  1459.                  sizeof(toc_trk_descr_t);
  1460.  
  1461.             toc_end = (byte_t *) h + bswap16(h->data_len) + 2;
  1462.  
  1463.             p = (toc_trk_descr_t *)(void *) cp;
  1464.         }
  1465.  
  1466.         s->trkinfo[i].trkno = p->trkno;
  1467.         s->trkinfo[i].type = (p->trktype == 0) ?
  1468.             TYP_AUDIO : TYP_DATA;
  1469.         s->trkinfo[i].min = p->abs_addr.msf.min;
  1470.         s->trkinfo[i].sec = p->abs_addr.msf.sec;
  1471.         s->trkinfo[i].frame = p->abs_addr.msf.frame;
  1472.         msftoblk(
  1473.             s->trkinfo[i].min,
  1474.             s->trkinfo[i].sec,
  1475.             s->trkinfo[i].frame,
  1476.             &s->trkinfo[i].addr,
  1477.             MSF_OFFSET(s)
  1478.         );
  1479.  
  1480.         if (p->trkno == LEAD_OUT_TRACK ||
  1481.             s->trkinfo[i-1].trkno == s->last_trk ||
  1482.             i == (MAXTRACK - 1)) {
  1483.             s->tot_min = s->trkinfo[i].min;
  1484.             s->tot_sec = s->trkinfo[i].sec;
  1485.             s->tot_frame = s->trkinfo[i].frame;
  1486.             s->tot_trks = i;
  1487.             s->tot_addr = s->trkinfo[i].addr;
  1488.  
  1489.             break;
  1490.         }
  1491.  
  1492.         cp += sizeof(toc_trk_descr_t);
  1493.     }
  1494.  
  1495.     return TRUE;
  1496. }
  1497.  
  1498.  
  1499. /*
  1500.  * scsipt_start_stat_poll
  1501.  *    Start polling the drive for current playback status
  1502.  *
  1503.  * Args:
  1504.  *    s - Pointer to the curstat_t structure
  1505.  *
  1506.  * Return:
  1507.  *    Nothing.
  1508.  */
  1509. STATIC void
  1510. scsipt_start_stat_poll(curstat_t *s)
  1511. {
  1512.     scsipt_stat_polling = TRUE;
  1513.  
  1514.     /* Start poll timer */
  1515.     scsipt_stat_id = cd_timeout(
  1516.         scsipt_stat_interval,
  1517.         scsipt_stat_poll,
  1518.         (byte_t *) s
  1519.     );
  1520. }
  1521.  
  1522.  
  1523. /*
  1524.  * scsipt_stop_stat_poll
  1525.  *    Stop polling the drive for current playback status
  1526.  *
  1527.  * Args:
  1528.  *    Nothing.
  1529.  *
  1530.  * Return:
  1531.  *    Nothing.
  1532.  */
  1533. STATIC void
  1534. scsipt_stop_stat_poll(void)
  1535. {
  1536.     if (scsipt_stat_polling) {
  1537.         /* Stop poll timer */
  1538.         cd_untimeout(scsipt_stat_id);
  1539.  
  1540.         scsipt_stat_polling = FALSE;
  1541.     }
  1542. }
  1543.  
  1544.  
  1545. /*
  1546.  * scsipt_start_insert_poll
  1547.  *    Start polling the drive for disc insertion
  1548.  *
  1549.  * Args:
  1550.  *    s - Pointer to the curstat_t structure
  1551.  *
  1552.  * Return:
  1553.  *    Nothing.
  1554.  */
  1555. STATIC void
  1556. scsipt_start_insert_poll(curstat_t *s)
  1557. {
  1558.     if (scsipt_insert_polling || s->mode != M_NODISC)
  1559.         return;
  1560.  
  1561.     scsipt_insert_polling = TRUE;
  1562.  
  1563.     /* Start poll timer */
  1564.     scsipt_insert_id = cd_timeout(
  1565.         app_data.ins_interval,
  1566.         scsipt_insert_poll,
  1567.         (byte_t *) s
  1568.     );
  1569. }
  1570.  
  1571.  
  1572. /*
  1573.  * scsipt_stop_insert_poll
  1574.  *    Stop polling the drive for disc insertion
  1575.  *
  1576.  * Args:
  1577.  *    s - Pointer to the curstat_t structure
  1578.  *
  1579.  * Return:
  1580.  *    Nothing.
  1581.  */
  1582. STATIC void
  1583. scsipt_stop_insert_poll(void)
  1584. {
  1585.     if (scsipt_insert_polling) {
  1586.         /* Stop poll timer */
  1587.         cd_untimeout(scsipt_insert_id);
  1588.  
  1589.         scsipt_insert_polling = FALSE;
  1590.     }
  1591. }
  1592.  
  1593.  
  1594. /*
  1595.  * stat_poll
  1596.  *    The playback status polling function
  1597.  *
  1598.  * Args:
  1599.  *    s - Pointer to the curstat_t structure
  1600.  *
  1601.  * Return:
  1602.  *    Nothing.
  1603.  */
  1604. STATIC void
  1605. scsipt_stat_poll(curstat_t *s)
  1606. {
  1607.     if (!scsipt_stat_polling)
  1608.         return;
  1609.  
  1610.     /* Get current audio playback status */
  1611.     if (scsipt_get_playstatus(s)) {
  1612.         /* Register next poll interval */
  1613.         scsipt_stat_id = cd_timeout(
  1614.             scsipt_stat_interval,
  1615.             scsipt_stat_poll,
  1616.             (byte_t *) s
  1617.         );
  1618.     }
  1619.     else
  1620.         scsipt_stat_polling = FALSE;
  1621. }
  1622.  
  1623.  
  1624. /*
  1625.  * insert_poll
  1626.  *    The disc insertion polling function
  1627.  *
  1628.  * Args:
  1629.  *    s - Pointer to the curstat_t structure
  1630.  *
  1631.  * Return:
  1632.  *    Nothing.
  1633.  */
  1634. STATIC void
  1635. scsipt_insert_poll(curstat_t *s)
  1636. {
  1637.     /* Check to see if a disc is inserted */
  1638.     if (!scsipt_disc_ready(s)) {
  1639.         /* Register next poll interval */
  1640.         scsipt_insert_id = cd_timeout(
  1641.             app_data.ins_interval,
  1642.             scsipt_insert_poll,
  1643.             (byte_t *) s
  1644.         );
  1645.     }
  1646.     else
  1647.         scsipt_insert_polling = FALSE;
  1648. }
  1649.  
  1650.  
  1651. /*
  1652.  * scsipt_disc_ready
  1653.  *    Check if the disc is loaded and ready for use, and update
  1654.  *    curstat table.
  1655.  *
  1656.  * Args:
  1657.  *    s - Pointer to the curstat_t structure
  1658.  *
  1659.  * Return:
  1660.  *    TRUE - Disc is ready
  1661.  *    FALSE - Disc is not ready
  1662.  */
  1663. STATIC bool_t
  1664. scsipt_disc_ready(curstat_t *s)
  1665. {
  1666.     int        i,
  1667.             vol;
  1668.     bool_t        err,
  1669.             first_open = FALSE;
  1670.  
  1671.     /* If device has not been opened, attempt to open it */
  1672.     if (scsipt_not_open) {
  1673.         /* Check for another copy of the CD player running on
  1674.          * the specified device.
  1675.          */
  1676.         if (!cd_devlock(app_data.device)) {
  1677.             dpy_time(s, FALSE);
  1678.             scsipt_start_insert_poll(s);
  1679.             return FALSE;
  1680.         }
  1681.  
  1682.         /* Open CD-ROM device */
  1683.         if (!pthru_open(app_data.device)) {
  1684.             dpy_time(s, FALSE);
  1685.             scsipt_start_insert_poll(s);
  1686.             return FALSE;
  1687.         }
  1688.  
  1689.         scsipt_not_open = FALSE;
  1690.         first_open = TRUE;
  1691.     }
  1692.  
  1693.     if (app_data.play_notur && s->mode != M_STOP && s->mode != M_NODISC) {
  1694.         /* For those drives that returns failure status to
  1695.          * the Test Unit Ready command during audio playback,
  1696.          * we just silently return success if the drive is
  1697.          * supposed to be playing audio.  Shrug.
  1698.          */
  1699.         err = FALSE;
  1700.     }
  1701.     else for (i = 0; i < 5; i++) {
  1702.         /* Send Test Unit Ready command to check if the
  1703.          * drive is ready.
  1704.          */
  1705.         if ((err = !scsipt_tst_unit_rdy()) == TRUE) {
  1706.             s->mode = M_NODISC;
  1707.             dbprog_dbclear(s);
  1708.         }
  1709.         else
  1710.             break;
  1711.     }
  1712.  
  1713.     if (!err && first_open) {
  1714.         /* Start up vendor-unique modules */
  1715.         if (scsipt_vutbl[app_data.vendor_code].start != NULL)
  1716.             scsipt_vutbl[app_data.vendor_code].start();
  1717.  
  1718.         /* Fill in inquiry data */
  1719.         scsipt_vendor_model(s);
  1720.  
  1721.         /* Query current volume and warp volume and balance
  1722.          * sliders to appropriate setting
  1723.          */
  1724.         if ((vol = scsipt_cfg_vol(0, s, TRUE, WARP_VOL | WARP_BAL)) >= 0)
  1725.             s->level = (byte_t) vol;
  1726.         else
  1727.             s->level = 0;
  1728.  
  1729.         /* Set up channel routing */
  1730.         scsipt_route(s);
  1731.     }
  1732.  
  1733.     /* Read disc table of contents */
  1734.     if (err || (s->mode == M_NODISC && !scsipt_get_toc(s))) {
  1735.         reset_curstat(s, TRUE);
  1736.         dpy_all(s);
  1737.  
  1738.         if (app_data.eject_close) {
  1739.             /* Close device */
  1740.             pthru_close();
  1741.  
  1742.             scsipt_not_open = TRUE;
  1743.         }
  1744.  
  1745.         scsipt_start_insert_poll(s);
  1746.         return FALSE;
  1747.     }
  1748.  
  1749.     if (s->mode == M_NODISC) {
  1750.         /* Load CD database entry for this disc */
  1751.         dbprog_dbget(s);
  1752.  
  1753.         s->mode = M_STOP;
  1754.         dpy_all(s);
  1755.  
  1756.         /* Disable front-panel eject button if so specified */
  1757.         if (app_data.caddy_lock)
  1758.             scsipt_lock(s, TRUE);
  1759.  
  1760.         if (app_data.load_play) {
  1761.             /* Start auto-play */
  1762.             scsipt_play_pause(s);
  1763.         }
  1764.         else if (app_data.load_spindown) {
  1765.             /* Spin down disc in case the user isn't going to
  1766.              * play anything for a while.  This reduces wear and
  1767.              * tear on the drive.
  1768.              */
  1769.             scsipt_do_start_stop(FALSE, FALSE);
  1770.         }
  1771.     }
  1772.  
  1773.     return TRUE;
  1774. }
  1775.  
  1776.  
  1777. /*
  1778.  * scsipt_run_rew
  1779.  *    Run search-rewind operation
  1780.  *
  1781.  * Args:
  1782.  *    s - Pointer to the curstat_t structure
  1783.  *
  1784.  * Return:
  1785.  *    Nothing.
  1786.  */
  1787. STATIC void
  1788. scsipt_run_rew(curstat_t *s)
  1789. {
  1790.     int        i,
  1791.             skip_blks;
  1792.     word32_t    addr,
  1793.             end_addr;
  1794.     msf_t        smsf,
  1795.             emsf;
  1796.     static word32_t    start_addr,
  1797.             seq;
  1798.  
  1799.     /* Find out where we are */
  1800.     if (!scsipt_get_playstatus(s)) {
  1801.         cd_beep();
  1802.         return;
  1803.     }
  1804.  
  1805.     skip_blks = app_data.skip_blks;
  1806.     addr = s->cur_tot_addr;
  1807.  
  1808.     if (scsipt_start_search) {
  1809.         scsipt_start_search = FALSE;
  1810.         seq = 0;
  1811.         if (skip_blks < addr)
  1812.             start_addr = addr - skip_blks;
  1813.         else
  1814.             start_addr = 0;
  1815.     }
  1816.     else {
  1817.         if (app_data.skip_spdup > 0 && seq > app_data.skip_spdup)
  1818.             /* Speed up search */
  1819.             skip_blks *= 3;
  1820.  
  1821.         if ((int) (start_addr - skip_blks) > 0)
  1822.             start_addr -= skip_blks;
  1823.         else
  1824.             start_addr = 0;
  1825.     }
  1826.  
  1827.     seq++;
  1828.  
  1829.     if (s->shuffle || s->program) {
  1830.         if ((i = curtrk_pos(s)) < 0)
  1831.             i = 0;
  1832.     }
  1833.     else
  1834.         i = 0;
  1835.  
  1836.     if (start_addr < s->trkinfo[i].addr)
  1837.         start_addr = s->trkinfo[i].addr;
  1838.  
  1839.     end_addr = start_addr + MAX_SRCH_BLKS;
  1840.  
  1841.     blktomsf(start_addr, &smsf.min, &smsf.sec, &smsf.frame, MSF_OFFSET(s));
  1842.     blktomsf(end_addr, &emsf.min, &emsf.sec, &emsf.frame, MSF_OFFSET(s));
  1843.  
  1844.     /* Play next search interval */
  1845.     scsipt_do_playaudio(
  1846.         ADDR_BLK | ADDR_MSF | ADDR_OPTEND,
  1847.         start_addr, end_addr,
  1848.         &smsf, &emsf,
  1849.         0, 0
  1850.     );
  1851.  
  1852.     scsipt_search_id = cd_timeout(
  1853.         app_data.skip_pause,
  1854.         scsipt_run_rew,
  1855.         (byte_t *) s
  1856.     );
  1857. }
  1858.  
  1859.  
  1860. /*
  1861.  * scsipt_stop_rew
  1862.  *    Stop search-rewind operation
  1863.  *
  1864.  * Args:
  1865.  *    s - Pointer to the curstat_t structure
  1866.  *
  1867.  * Return:
  1868.  *    Nothing.
  1869.  */
  1870. /*ARGSUSED*/
  1871. STATIC void
  1872. scsipt_stop_rew(curstat_t *s)
  1873. {
  1874.     cd_untimeout(scsipt_search_id);
  1875. }
  1876.  
  1877.  
  1878. /*
  1879.  * scsipt_run_ff
  1880.  *    Run search-fast-forward operation
  1881.  *
  1882.  * Args:
  1883.  *    s - Pointer to the curstat_t structure
  1884.  *
  1885.  * Return:
  1886.  *    Nothing.
  1887.  */
  1888. STATIC void
  1889. scsipt_run_ff(curstat_t *s)
  1890. {
  1891.     int        i,
  1892.             skip_blks;
  1893.     word32_t    addr,
  1894.             end_addr;
  1895.     msf_t        smsf,
  1896.             emsf;
  1897.     static word32_t    start_addr,
  1898.             seq;
  1899.  
  1900.     /* Find out where we are */
  1901.     if (!scsipt_get_playstatus(s)) {
  1902.         cd_beep();
  1903.         return;
  1904.     }
  1905.  
  1906.     skip_blks = app_data.skip_blks;
  1907.     addr = s->cur_tot_addr;
  1908.  
  1909.     if (scsipt_start_search) {
  1910.         scsipt_start_search = FALSE;
  1911.         seq = 0;
  1912.         start_addr = addr + skip_blks;
  1913.     }
  1914.     else {
  1915.         if (app_data.skip_spdup > 0 && seq > app_data.skip_spdup)
  1916.             /* Speed up search */
  1917.             skip_blks *= 3;
  1918.  
  1919.         start_addr += skip_blks;
  1920.     }
  1921.  
  1922.     seq++;
  1923.  
  1924.     if (s->shuffle || s->program) {
  1925.         if ((i = curtrk_pos(s)) < 0)
  1926.             i = s->tot_trks - 1;
  1927.         else if (s->cur_idx == 0)
  1928.             /* We're in the lead-in: consider this to be
  1929.              * within the previous track.
  1930.              */
  1931.             i--;
  1932.     }
  1933.     else
  1934.         i = s->tot_trks - 1;
  1935.  
  1936.     end_addr = start_addr + MAX_SRCH_BLKS;
  1937.  
  1938.     if (end_addr >= s->trkinfo[i+1].addr) {
  1939.         end_addr = s->trkinfo[i+1].addr;
  1940.         start_addr = end_addr - skip_blks;
  1941.     }
  1942.  
  1943.     blktomsf(start_addr, &smsf.min, &smsf.sec, &smsf.frame, MSF_OFFSET(s));
  1944.     blktomsf(end_addr, &emsf.min, &emsf.sec, &emsf.frame, MSF_OFFSET(s));
  1945.  
  1946.     /* Play next search interval */
  1947.     scsipt_do_playaudio(
  1948.         ADDR_BLK | ADDR_MSF | ADDR_OPTEND,
  1949.         start_addr, end_addr,
  1950.         &smsf, &emsf,
  1951.         0, 0
  1952.     );
  1953.  
  1954.     scsipt_search_id = cd_timeout(
  1955.         app_data.skip_pause,
  1956.         scsipt_run_ff,
  1957.         (byte_t *) s
  1958.     );
  1959. }
  1960.  
  1961.  
  1962. /*
  1963.  * scsipt_stop_ff
  1964.  *    Stop search-fast-forward operation
  1965.  *
  1966.  * Args:
  1967.  *    s - Pointer to the curstat_t structure
  1968.  *
  1969.  * Return:
  1970.  *    Nothing.
  1971.  */
  1972. /*ARGSUSED*/
  1973. STATIC void
  1974. scsipt_stop_ff(curstat_t *s)
  1975. {
  1976.     cd_untimeout(scsipt_search_id);
  1977. }
  1978.  
  1979.  
  1980. /*
  1981.  * scsipt_run_ab
  1982.  *    Run a->b segment play operation
  1983.  *
  1984.  * Args:
  1985.  *    s - Pointer to the curstat_t structure
  1986.  *
  1987.  * Return:
  1988.  *    TRUE - success
  1989.  *    FALSE - failure
  1990.  */
  1991. /*ARGSUSED*/
  1992. STATIC bool_t
  1993. scsipt_run_ab(curstat_t *s)
  1994. {
  1995.     return (
  1996.         scsipt_do_playaudio(
  1997.             ADDR_BLK | ADDR_MSF,
  1998.             scsipt_ab_start_addr, scsipt_ab_end_addr,
  1999.             &scsipt_ab_start_msf, &scsipt_ab_end_msf,
  2000.             0, 0
  2001.         )
  2002.     );
  2003. }
  2004.  
  2005.  
  2006. /*
  2007.  * scsipt_run_sample
  2008.  *    Run sample play operation
  2009.  *
  2010.  * Args:
  2011.  *    s - Pointer to the curstat_t structure
  2012.  *
  2013.  * Return:
  2014.  *    TRUE - success
  2015.  *    FALSE - failure
  2016.  */
  2017. STATIC bool_t
  2018. scsipt_run_sample(curstat_t *s)
  2019. {
  2020.     word32_t    saddr,
  2021.             eaddr;
  2022.     msf_t        smsf,
  2023.             emsf;
  2024.  
  2025.     if (scsipt_next_sam < s->tot_trks) {
  2026.         saddr = s->trkinfo[scsipt_next_sam].addr;
  2027.         eaddr = saddr + app_data.sample_blks,
  2028.  
  2029.         blktomsf(
  2030.             saddr,
  2031.             &smsf.min,
  2032.             &smsf.sec,
  2033.             &smsf.frame,
  2034.             MSF_OFFSET(s)
  2035.         );
  2036.         blktomsf(
  2037.             eaddr,
  2038.             &emsf.min,
  2039.             &emsf.sec,
  2040.             &emsf.frame,
  2041.             MSF_OFFSET(s)
  2042.         );
  2043.  
  2044.         if (scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  2045.                  saddr, eaddr, &smsf, &emsf, 0, 0)) {
  2046.             scsipt_next_sam++;
  2047.             return TRUE;
  2048.         }
  2049.     }
  2050.  
  2051.     scsipt_next_sam = 0;
  2052.     return FALSE;
  2053. }
  2054.  
  2055.  
  2056. /*
  2057.  * scsipt_run_prog
  2058.  *    Run program/shuffle play operation
  2059.  *
  2060.  * Args:
  2061.  *    s - Pointer to the curstat_t structure
  2062.  *
  2063.  * Return:
  2064.  *    TRUE - success
  2065.  *    FALSE - failure
  2066.  */
  2067. STATIC bool_t
  2068. scsipt_run_prog(curstat_t *s)
  2069. {
  2070.     sword32_t    i;
  2071.     word32_t    start_addr,
  2072.             end_addr;
  2073.     msf_t        start_msf,
  2074.             end_msf;
  2075.     bool_t        ret;
  2076.  
  2077.     if (!s->shuffle && s->prog_tot <= 0)
  2078.         return FALSE;
  2079.  
  2080.     if (scsipt_new_progshuf) {
  2081.         if (s->shuffle)
  2082.             /* New shuffle sequence needed */
  2083.             reset_shuffle(s);
  2084.         else
  2085.             /* Program play: simply reset the count */
  2086.             s->prog_cnt = 0;
  2087.  
  2088.         scsipt_new_progshuf = FALSE;
  2089.     }
  2090.  
  2091.     if (s->prog_cnt >= s->prog_tot)
  2092.         /* Done with program/shuffle play cycle */
  2093.         return FALSE;
  2094.  
  2095.     if ((i = curprog_pos(s)) < 0)
  2096.         return FALSE;
  2097.  
  2098.     if (s->trkinfo[i].trkno == LEAD_OUT_TRACK)
  2099.         return FALSE;
  2100.  
  2101.     s->prog_cnt++;
  2102.     s->cur_trk = s->trkinfo[i].trkno;
  2103.     s->cur_idx = 1;
  2104.  
  2105.     start_addr = s->trkinfo[i].addr + s->cur_trk_addr;
  2106.     blktomsf(
  2107.         start_addr,
  2108.         &s->cur_tot_min,
  2109.         &s->cur_tot_sec,
  2110.         &s->cur_tot_frame,
  2111.         MSF_OFFSET(s)
  2112.     );
  2113.     start_msf.min = s->cur_tot_min;
  2114.     start_msf.sec = s->cur_tot_sec;
  2115.     start_msf.frame = s->cur_tot_frame;
  2116.  
  2117.     end_addr = s->trkinfo[i+1].addr;
  2118.     end_msf.min = s->trkinfo[i+1].min;
  2119.     end_msf.sec = s->trkinfo[i+1].sec;
  2120.     end_msf.frame = s->trkinfo[i+1].frame;
  2121.  
  2122.     s->cur_tot_addr = start_addr;
  2123.  
  2124.     if (s->mode != M_PAUSE)
  2125.         s->mode = M_PLAY;
  2126.  
  2127.     dpy_all(s);
  2128.  
  2129.     if (s->trkinfo[i].type == TYP_DATA)
  2130.         /* Data track: just fake it */
  2131.         return TRUE;
  2132.  
  2133.     ret = scsipt_do_playaudio(
  2134.         ADDR_BLK | ADDR_MSF,
  2135.         start_addr, end_addr,
  2136.         &start_msf, &end_msf,
  2137.         0, 0
  2138.     );
  2139.  
  2140.     if (s->mode == M_PAUSE) {
  2141.         scsipt_do_pause_resume(FALSE);
  2142.  
  2143.         /* Restore volume */
  2144.         scsipt_mute_off(s);
  2145.     }
  2146.  
  2147.     return (ret);
  2148. }
  2149.  
  2150.  
  2151. /*
  2152.  * scsipt_run_repeat
  2153.  *    Run repeat play operation
  2154.  *
  2155.  * Args:
  2156.  *    s - Pointer to the curstat_t structure
  2157.  *
  2158.  * Return:
  2159.  *    TRUE - success
  2160.  *    FALSE - failure
  2161.  */
  2162. STATIC bool_t
  2163. scsipt_run_repeat(curstat_t *s)
  2164. {
  2165.     msf_t    start_msf,
  2166.         end_msf;
  2167.     int    ret;
  2168.  
  2169.     if (!s->repeat)
  2170.         return FALSE;
  2171.  
  2172.     if (s->prog_tot > 0) {
  2173.         ret = TRUE;
  2174.  
  2175.         if (s->prog_cnt < s->prog_tot)
  2176.             /* Not done with program/shuffle sequence yet */
  2177.             return (ret);
  2178.  
  2179.         scsipt_new_progshuf = TRUE;
  2180.         s->rptcnt++;
  2181.     }
  2182.     else {
  2183.         s->cur_trk = s->first_trk;
  2184.         s->cur_idx = 1;
  2185.  
  2186.         s->cur_tot_addr = 0;
  2187.         s->cur_tot_min = 0;
  2188.         s->cur_tot_sec = 0;
  2189.         s->cur_tot_frame = 0;
  2190.         s->rptcnt++;
  2191.         dpy_all(s);
  2192.  
  2193.         start_msf.min = s->trkinfo[0].min;
  2194.         start_msf.sec = s->trkinfo[0].sec;
  2195.         start_msf.frame = s->trkinfo[0].frame;
  2196.         end_msf.min = s->tot_min;
  2197.         end_msf.sec = s->tot_sec;
  2198.         end_msf.frame = s->tot_frame;
  2199.  
  2200.         ret = scsipt_do_playaudio(
  2201.             ADDR_BLK | ADDR_MSF,
  2202.             s->trkinfo[0].addr, s->tot_addr,
  2203.             &start_msf, &end_msf, 0, 0
  2204.         );
  2205.  
  2206.         if (s->mode == M_PAUSE) {
  2207.             scsipt_do_pause_resume(FALSE);
  2208.  
  2209.             /* Restore volume */
  2210.             scsipt_mute_off(s);
  2211.         }
  2212.  
  2213.     }
  2214.  
  2215.     return (ret);
  2216. }
  2217.  
  2218.  
  2219. /*
  2220.  * scsipt_route_val
  2221.  *    Return the channel routing control value used in the
  2222.  *    SCSI-2 mode parameter page 0xE (audio parameters).
  2223.  *
  2224.  * Args:
  2225.  *    route_mode - The channel routing mode value.
  2226.  *    channel - The channel number desired (0=left 1=right).
  2227.  *
  2228.  * Return:
  2229.  *    The routing control value.
  2230.  */
  2231. STATIC byte_t
  2232. scsipt_route_val(int route_mode, int channel)
  2233. {
  2234.     switch (channel) {
  2235.     case 0:
  2236.         switch (route_mode) {
  2237.         case 0:
  2238.             return 0x1;
  2239.             break;
  2240.         case 1:
  2241.             return 0x2;
  2242.             break;
  2243.         case 2:
  2244.             return 0x1;
  2245.             break;
  2246.         case 3:
  2247.             return 0x2;
  2248.             break;
  2249.         case 4:
  2250.             return 0x3;
  2251.             break;
  2252.         default:
  2253.             /* Invalid value */
  2254.             return 0x0;
  2255.             break;
  2256.         }
  2257.         break;
  2258.  
  2259.     case 1:
  2260.         switch (route_mode) {
  2261.         case 0:
  2262.             return 0x2;
  2263.             break;
  2264.         case 1:
  2265.             return 0x1;
  2266.             break;
  2267.         case 2:
  2268.             return 0x1;
  2269.             break;
  2270.         case 3:
  2271.             return 0x2;
  2272.             break;
  2273.         case 4:
  2274.             return 0x3;
  2275.             break;
  2276.         default:
  2277.             /* Invalid value */
  2278.             return 0x0;
  2279.             break;
  2280.         }
  2281.         break;
  2282.  
  2283.     default:
  2284.         /* Invalid value */
  2285.         return 0x0;
  2286.     }
  2287. }
  2288.  
  2289.  
  2290. /***********************
  2291.  *   public routines   *
  2292.  ***********************/
  2293.  
  2294.  
  2295. /*
  2296.  * scsipt_init
  2297.  *    Top-level function to initialize the SCSI pass-through and
  2298.  *    vendor-unique modules.
  2299.  *
  2300.  * Args:
  2301.  *    s - Pointer to the curstat_t structure
  2302.  *
  2303.  * Return:
  2304.  *    Nothing.
  2305.  */
  2306. void
  2307. scsipt_init(curstat_t *s, di_tbl_t *dt)
  2308. {
  2309.     int    i;
  2310.  
  2311.     if (app_data.di_method != DI_SCSIPT)
  2312.         /* SCSI pass-through not configured */
  2313.         return;
  2314.  
  2315.     /* Initialize libdi calling table */
  2316.     dt->check_disc = scsipt_check_disc;
  2317.     dt->status_upd = scsipt_status_upd;
  2318.     dt->lock = scsipt_lock;
  2319.     dt->repeat = scsipt_repeat;
  2320.     dt->shuffle = scsipt_shuffle;
  2321.     dt->load_eject = scsipt_load_eject;
  2322.     dt->ab = scsipt_ab;
  2323.     dt->sample = scsipt_sample;
  2324.     dt->level = scsipt_level;
  2325.     dt->play_pause = scsipt_play_pause;
  2326.     dt->stop = scsipt_stop;
  2327.     dt->prevtrk = scsipt_prevtrk;
  2328.     dt->nexttrk = scsipt_nexttrk;
  2329.     dt->previdx = scsipt_previdx;
  2330.     dt->nextidx = scsipt_nextidx;
  2331.     dt->rew = scsipt_rew;
  2332.     dt->ff = scsipt_ff;
  2333.     dt->warp = scsipt_warp;
  2334.     dt->route = scsipt_route;
  2335.     dt->mute_on = scsipt_mute_on;
  2336.     dt->mute_off = scsipt_mute_off;
  2337.     dt->start = scsipt_start;
  2338.     dt->icon = scsipt_icon;
  2339.     dt->halt = scsipt_halt;
  2340.     dt->mode = scsipt_mode;
  2341.     dt->vers = scsipt_vers;
  2342.  
  2343.     /* Initalize SCSI pass-through module */
  2344.     scsipt_stat_polling = FALSE;
  2345.     scsipt_stat_interval = app_data.stat_interval;
  2346.     scsipt_insert_polling = FALSE;
  2347.     scsipt_next_sam = FALSE;
  2348.     scsipt_new_progshuf = FALSE;
  2349.     scsipt_sav_end_addr = 0;
  2350.     scsipt_sav_end_msf.min = scsipt_sav_end_msf.sec =
  2351.         scsipt_sav_end_msf.frame = 0;
  2352.     scsipt_sav_end_fmt = 0;
  2353.  
  2354. #ifdef SETUID_ROOT
  2355. #ifdef SOL2_VOLMGT
  2356.     if (!app_data.sol2_volmgt)
  2357. #endif    /* SOL2_VOLMGT */
  2358.     {
  2359.         DBGPRN(errfp, "\nSetting uid to 0\n");
  2360.  
  2361.         if (setuid(0) < 0 || getuid() != 0) {
  2362.             cd_fatal_popup(app_data.str_fatal,
  2363.                        app_data.str_moderr);
  2364.         }
  2365.     }
  2366. #endif    /* SETUID_ROOT */
  2367.  
  2368.     /* Initialize curstat structure */
  2369.     reset_curstat(s, TRUE);
  2370.  
  2371.     /* Initialize the SCSI-2 entry of the scsipt_vutbl jump table */
  2372.     scsipt_vutbl[VENDOR_SCSI2].vendor = "SCSI-2";
  2373.     scsipt_vutbl[VENDOR_SCSI2].playaudio = NULL;
  2374.     scsipt_vutbl[VENDOR_SCSI2].pause_resume = NULL;
  2375.     scsipt_vutbl[VENDOR_SCSI2].start_stop = NULL;
  2376.     scsipt_vutbl[VENDOR_SCSI2].get_playstatus = NULL;
  2377.     scsipt_vutbl[VENDOR_SCSI2].volume = NULL;
  2378.     scsipt_vutbl[VENDOR_SCSI2].route = NULL;
  2379.     scsipt_vutbl[VENDOR_SCSI2].mute = NULL;
  2380.     scsipt_vutbl[VENDOR_SCSI2].get_toc = NULL;
  2381.     scsipt_vutbl[VENDOR_SCSI2].eject = NULL;
  2382.     scsipt_vutbl[VENDOR_SCSI2].start = NULL;
  2383.     scsipt_vutbl[VENDOR_SCSI2].halt = NULL;
  2384.  
  2385.     /* Initialize all configured vendor-unique modules */
  2386.     for (i = 0; i < MAX_VENDORS; i++) {
  2387.         if (vuinit[i].init != NULL)
  2388.             vuinit[i].init();
  2389.     }
  2390.  
  2391.     if (app_data.vendor_code != VENDOR_SCSI2 &&
  2392.         vuinit[app_data.vendor_code].init == NULL) {
  2393.         cd_fatal_popup(app_data.str_fatal, app_data.str_novu);
  2394.     }
  2395. }
  2396.  
  2397.  
  2398. /*
  2399.  * scsipt_check_disc
  2400.  *    Check if disc is ready for use
  2401.  *
  2402.  * Args:
  2403.  *    s - Pointer to the curstat_t structure
  2404.  *
  2405.  * Return:
  2406.  *    TRUE - success
  2407.  *    FALSE - failure
  2408.  */
  2409. bool_t
  2410. scsipt_check_disc(curstat_t *s)
  2411. {
  2412.     return (scsipt_disc_ready(s));
  2413. }
  2414.  
  2415.  
  2416. /*
  2417.  * scsipt_status_upd
  2418.  *    Force update of playback status
  2419.  *
  2420.  * Args:
  2421.  *    s - Pointer to the curstat_t structure
  2422.  *
  2423.  * Return:
  2424.  *    Nothing.
  2425.  */
  2426. void
  2427. scsipt_status_upd(curstat_t *s)
  2428. {
  2429.     scsipt_get_playstatus(s);
  2430. }
  2431.  
  2432.  
  2433. /*
  2434.  * scsipt_lock
  2435.  *    Caddy lock function
  2436.  *
  2437.  * Args:
  2438.  *    s - Pointer to the curstat_t structure
  2439.  *    enable - whether to enable/disable caddy lock
  2440.  *
  2441.  * Return:
  2442.  *    Nothing.
  2443.  */
  2444. void
  2445. scsipt_lock(curstat_t *s, bool_t enable)
  2446. {
  2447.     if (s->mode == M_NODISC || !scsipt_prev_allow(enable)) {
  2448.         /* Cannot lock/unlock caddy */
  2449.         cd_beep();
  2450.         set_lock_btn((bool_t) !enable);
  2451.         return;
  2452.     }
  2453.  
  2454.     s->caddy_lock = enable;
  2455.     set_lock_btn((bool_t) enable);
  2456. }
  2457.  
  2458.  
  2459. /*
  2460.  * scsipt_repeat
  2461.  *    Repeat mode function
  2462.  *
  2463.  * Args:
  2464.  *    s - Pointer to the curstat_t structure
  2465.  *    enable - whether to enable/disable repeat mode
  2466.  *
  2467.  * Return:
  2468.  *    Nothing.
  2469.  */
  2470. void
  2471. scsipt_repeat(curstat_t *s, bool_t enable)
  2472. {
  2473.     s->repeat = enable;
  2474.     dpy_rptcnt(s);
  2475. }
  2476.  
  2477.  
  2478. /*
  2479.  * scsipt_shuffle
  2480.  *    Shuffle mode function
  2481.  *
  2482.  * Args:
  2483.  *    s - Pointer to the curstat_t structure
  2484.  *    enable - whether to enable/disable shuffle mode
  2485.  *
  2486.  * Return:
  2487.  *    Nothing.
  2488.  */
  2489. void
  2490. scsipt_shuffle(curstat_t *s, bool_t enable)
  2491. {
  2492.     switch (s->mode) {
  2493.     case M_STOP:
  2494.     case M_NODISC:
  2495.         if (s->prog_tot > 0 && !s->shuffle) {
  2496.             /* Currently in program mode: can't enable shuffle */
  2497.             cd_beep();
  2498.             set_shuffle_btn((bool_t) !enable);
  2499.             return;
  2500.         }
  2501.         break;
  2502.     default:
  2503.         if (enable) {
  2504.             /* Can't enable shuffle unless when stopped */
  2505.             cd_beep();
  2506.             set_shuffle_btn((bool_t) !enable);
  2507.             return;
  2508.         }
  2509.         break;
  2510.     }
  2511.  
  2512.     s->shuffle = enable;
  2513.     if (!s->shuffle)
  2514.         s->prog_tot = 0;
  2515. }
  2516.  
  2517.  
  2518. /*
  2519.  * scsipt_load_eject
  2520.  *    CD caddy load and eject function.  If disc caddy is not
  2521.  *    loaded, it will attempt to load it.  Otherwise, it will be
  2522.  *    ejected.
  2523.  *
  2524.  * Args:
  2525.  *    s - Pointer to the curstat_t structure
  2526.  *
  2527.  * Return:
  2528.  *    Nothing.
  2529.  */
  2530. void
  2531. scsipt_load_eject(curstat_t *s)
  2532. {
  2533.     bool_t    ret = FALSE;
  2534.  
  2535.     if (!scsipt_disc_ready(s)) {
  2536.         /* Disc not ready: try loading the disc */
  2537.         if (!scsipt_do_start_stop(TRUE, TRUE))
  2538.             cd_beep();
  2539.  
  2540.         return;
  2541.     }
  2542.  
  2543.     /* Eject the disc */
  2544.  
  2545.     if (!app_data.eject_supp) {
  2546.         cd_beep();
  2547.  
  2548.         scsipt_stop_stat_poll();
  2549.         reset_curstat(s, TRUE);
  2550.         s->mode = M_NODISC;
  2551.  
  2552.         dbprog_dbclear(s);
  2553.         dpy_all(s);
  2554.  
  2555.         if (app_data.eject_close) {
  2556.             /* Close device */
  2557.             pthru_close();
  2558.  
  2559.             scsipt_not_open = TRUE;
  2560.         }
  2561.  
  2562.         scsipt_start_insert_poll(s);
  2563.         return;
  2564.     }
  2565.  
  2566.     /* Unlock caddy if necessary */
  2567.     if (s->caddy_lock)
  2568.         scsipt_lock(s, FALSE);
  2569.  
  2570.     scsipt_stop_stat_poll();
  2571.     reset_curstat(s, TRUE);
  2572.     s->mode = M_NODISC;
  2573.  
  2574.     dbprog_dbclear(s);
  2575.     dpy_all(s);
  2576.  
  2577.     scsipt_do_start_stop(FALSE, TRUE);
  2578.  
  2579.     if (app_data.eject_exit)
  2580.         cd_quit(s);
  2581.     else {
  2582.         if (app_data.eject_close) {
  2583.             /* Close device */
  2584.             pthru_close();
  2585.  
  2586.             scsipt_not_open = TRUE;
  2587.         }
  2588.  
  2589.         scsipt_start_insert_poll(s);
  2590.     }
  2591. }
  2592.  
  2593.  
  2594. /*
  2595.  * scsipt_ab
  2596.  *    A->B segment play mode function
  2597.  *
  2598.  * Args:
  2599.  *    s - Pointer to the curstat_t structure
  2600.  *
  2601.  * Return:
  2602.  *    Nothing.
  2603.  */
  2604. void
  2605. scsipt_ab(curstat_t *s)
  2606. {
  2607.     switch (s->mode) {
  2608.     case M_SAMPLE:
  2609.     case M_PLAY:
  2610.         /* Get current location */
  2611.         if (!scsipt_get_playstatus(s)) {
  2612.             cd_beep();
  2613.             break;
  2614.         }
  2615.  
  2616.         scsipt_ab_start_addr = s->cur_tot_addr;
  2617.         scsipt_ab_start_msf.min = s->cur_tot_min;
  2618.         scsipt_ab_start_msf.sec = s->cur_tot_sec;
  2619.         scsipt_ab_start_msf.frame = s->cur_tot_frame;
  2620.  
  2621.         s->mode = M_A;
  2622.         dpy_playmode(s, FALSE);
  2623.         break;
  2624.  
  2625.     case M_A:
  2626.         /* Get current location */
  2627.         if (!scsipt_get_playstatus(s)) {
  2628.             cd_beep();
  2629.             break;
  2630.         }
  2631.  
  2632.         scsipt_ab_end_addr = s->cur_tot_addr;
  2633.         scsipt_ab_end_msf.min = s->cur_tot_min;
  2634.         scsipt_ab_end_msf.sec = s->cur_tot_sec;
  2635.         scsipt_ab_end_msf.frame = s->cur_tot_frame;
  2636.  
  2637.         /* Make sure that the A->B play interval is no less
  2638.          * than a user-configurable minimum.
  2639.          */
  2640.         if ((scsipt_ab_end_addr - scsipt_ab_start_addr) <
  2641.             app_data.min_playblks) {
  2642.             scsipt_ab_end_addr = scsipt_ab_start_addr +
  2643.                          app_data.min_playblks;
  2644.             blktomsf(
  2645.                 scsipt_ab_end_addr,
  2646.                 &scsipt_ab_end_msf.min,
  2647.                 &scsipt_ab_end_msf.sec,
  2648.                 &scsipt_ab_end_msf.frame,
  2649.                 MSF_OFFSET(s)
  2650.             );
  2651.         }
  2652.  
  2653.         if (!scsipt_run_ab(s)) {
  2654.             cd_beep();
  2655.             return;
  2656.         }
  2657.  
  2658.         s->mode = M_AB;
  2659.         dpy_playmode(s, FALSE);
  2660.         break;
  2661.  
  2662.     case M_AB:
  2663.         /* Currently doing A->B playback, just call scsipt_play_pause
  2664.          * to resume normal playback.
  2665.          */
  2666.         scsipt_play_pause(s);
  2667.         break;
  2668.  
  2669.     default:
  2670.         cd_beep();
  2671.         break;
  2672.     }
  2673. }
  2674.  
  2675.  
  2676. /*
  2677.  * scsipt_sample
  2678.  *    Sample play mode function
  2679.  *
  2680.  * Args:
  2681.  *    s - Pointer to the curstat_t structure
  2682.  *
  2683.  * Return:
  2684.  *    Nothing.
  2685.  */
  2686. void
  2687. scsipt_sample(curstat_t *s)
  2688. {
  2689.     int    i;
  2690.  
  2691.     if (!scsipt_disc_ready(s)) {
  2692.         cd_beep();
  2693.         return;
  2694.     }
  2695.  
  2696.     if (s->shuffle || s->prog_tot > 0) {
  2697.         /* Sample is not supported in program/shuffle mode */
  2698.         cd_beep();
  2699.         return;
  2700.     }
  2701.  
  2702.     switch (s->mode) {
  2703.     case M_STOP:
  2704.         scsipt_start_stat_poll(s);
  2705.         /*FALLTHROUGH*/
  2706.     case M_A:
  2707.     case M_AB:
  2708.     case M_PLAY:
  2709.         /* If already playing a track, start sampling the track after
  2710.          * the current one.  Otherwise, sample from the beginning.
  2711.          */
  2712.         if (s->cur_trk > 0 && s->cur_trk != s->last_trk) {
  2713.             i = curtrk_pos(s) + 1;
  2714.             s->cur_trk = s->trkinfo[i].trkno;
  2715.             scsipt_next_sam = i;
  2716.         }
  2717.         else {
  2718.             s->cur_trk = s->first_trk;
  2719.             scsipt_next_sam = 0;
  2720.         }
  2721.         
  2722.         s->cur_idx = 1;
  2723.  
  2724.         s->mode = M_SAMPLE;
  2725.         dpy_all(s);
  2726.  
  2727.         if (!scsipt_run_sample(s))
  2728.             return;
  2729.  
  2730.         break;
  2731.  
  2732.     case M_SAMPLE:
  2733.         /* Currently doing Sample playback, just call scsipt_play_pause
  2734.          * to resume normal playback.
  2735.          */
  2736.         scsipt_play_pause(s);
  2737.         break;
  2738.  
  2739.     default:
  2740.         cd_beep();
  2741.         break;
  2742.     }
  2743. }
  2744.  
  2745.  
  2746. /*
  2747.  * scsipt_level
  2748.  *    Audio volume control function
  2749.  *
  2750.  * Args:
  2751.  *    s - Pointer to the curstat_t structure
  2752.  *    level - The volume level to set to
  2753.  *    drag - Whether this is an update due to the user dragging the
  2754.  *        volume control slider thumb.  If this is FALSE, then
  2755.  *        a final volume setting has been found.
  2756.  *
  2757.  * Return:
  2758.  *    Nothing.
  2759.  */
  2760. void
  2761. scsipt_level(curstat_t *s, byte_t level, bool_t drag)
  2762. {
  2763.     int    actual;
  2764.     byte_t    warpflg;
  2765.  
  2766.     if (drag && app_data.vendor_code != VENDOR_SCSI2 &&
  2767.         scsipt_vutbl[app_data.vendor_code].volume == NULL)
  2768.         return;
  2769.  
  2770.     if (drag)
  2771.         warpflg = WARP_VOL;
  2772.     else
  2773.         warpflg = WARP_VOL | WARP_BAL;
  2774.  
  2775.     /* Set volume level */
  2776.     if ((actual = scsipt_cfg_vol((int) level, s, FALSE, warpflg)) >= 0)
  2777.         s->level = (byte_t) actual;
  2778. }
  2779.  
  2780.  
  2781. /*
  2782.  * scsipt_play_pause
  2783.  *    Audio playback and pause function
  2784.  *
  2785.  * Args:
  2786.  *    s - Pointer to the curstat_t structure
  2787.  *
  2788.  * Return:
  2789.  *    Nothing.
  2790.  */
  2791. void
  2792. scsipt_play_pause(curstat_t *s)
  2793. {
  2794.     sword32_t    i;
  2795.     word32_t    start_addr;
  2796.     msf_t        start_msf,
  2797.             end_msf;
  2798.  
  2799.     if (!scsipt_disc_ready(s)) {
  2800.         cd_beep();
  2801.         return;
  2802.     }
  2803.  
  2804.     if (s->mode == M_NODISC)
  2805.         s->mode = M_STOP;
  2806.  
  2807.     switch (s->mode) {
  2808.     case M_PLAY:
  2809.         /* Currently playing: go to pause mode */
  2810.  
  2811.         if (!scsipt_do_pause_resume(FALSE)) {
  2812.             cd_beep();
  2813.             return;
  2814.         }
  2815.         scsipt_stop_stat_poll();
  2816.         s->mode = M_PAUSE;
  2817.         dpy_playmode(s, FALSE);
  2818.         break;
  2819.  
  2820.     case M_PAUSE:
  2821.         /* Currently paused: resume play */
  2822.  
  2823.         if (!scsipt_do_pause_resume(TRUE)) {
  2824.             cd_beep();
  2825.             return;
  2826.         }
  2827.         s->mode = M_PLAY;
  2828.         dpy_playmode(s, FALSE);
  2829.         scsipt_start_stat_poll(s);
  2830.         break;
  2831.  
  2832.     case M_STOP:
  2833.         /* Currently stopped: start play */
  2834.  
  2835.         if (s->shuffle || s->prog_tot > 0) {
  2836.             scsipt_new_progshuf = TRUE;
  2837.  
  2838.             /* Start shuffle/program play */
  2839.             if (!scsipt_run_prog(s)) {
  2840.                 s->program = FALSE;
  2841.                 return;
  2842.             }
  2843.  
  2844.             s->program = !s->shuffle;
  2845.         }
  2846.         else {
  2847.             /* Start normal play */
  2848.             if ((i = curtrk_pos(s)) < 0 || s->cur_trk <= 0) {
  2849.                 /* Start play from the beginning */
  2850.                 i = 0;
  2851.                 s->cur_trk = s->first_trk;
  2852.                 start_addr = s->trkinfo[0].addr +
  2853.                          s->cur_trk_addr;
  2854.                 blktomsf(start_addr,
  2855.                      &start_msf.min,
  2856.                      &start_msf.sec,
  2857.                      &start_msf.frame,
  2858.                      MSF_OFFSET(s)
  2859.                 );
  2860.             }
  2861.             else {
  2862.                 /* User has specified a starting track */
  2863.                 start_addr = s->trkinfo[i].addr +
  2864.                          s->cur_trk_addr;
  2865.             }
  2866.  
  2867.             blktomsf(start_addr,
  2868.                  &start_msf.min,
  2869.                  &start_msf.sec,
  2870.                  &start_msf.frame,
  2871.                  MSF_OFFSET(s)
  2872.             );
  2873.  
  2874.             end_msf.min = s->tot_min;
  2875.             end_msf.sec = s->tot_sec;
  2876.             end_msf.frame = s->tot_frame;
  2877.  
  2878.             s->cur_idx = 1;
  2879.             s->mode = M_PLAY;
  2880.             if (s->trkinfo[i].type == TYP_DATA)
  2881.                 dpy_time(s, FALSE);
  2882.  
  2883.             if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  2884.                       start_addr, s->tot_addr,
  2885.                       &start_msf, &end_msf, 0, 0)) {
  2886.                 cd_beep();
  2887.                 s->mode = M_STOP;
  2888.                 return;
  2889.             }
  2890.         }
  2891.  
  2892.         dpy_all(s);
  2893.         scsipt_start_stat_poll(s);
  2894.         break;
  2895.  
  2896.     case M_A:
  2897.         /* Just reset mode to play and continue */
  2898.         s->mode = M_PLAY;
  2899.         dpy_playmode(s, FALSE);
  2900.         break;
  2901.  
  2902.     case M_AB:
  2903.     case M_SAMPLE:
  2904.         /* Force update of curstat */
  2905.         if (!scsipt_get_playstatus(s)) {
  2906.             cd_beep();
  2907.             return;
  2908.         }
  2909.  
  2910.         /* Currently doing a->b or sample playback: just resume play */
  2911.         if (s->shuffle || s->program) {
  2912.             if ((i = curtrk_pos(s)) < 0 ||
  2913.                 s->trkinfo[i].trkno == LEAD_OUT_TRACK)
  2914.                 return;
  2915.  
  2916.             start_msf.min = s->cur_tot_min;
  2917.             start_msf.sec = s->cur_tot_sec;
  2918.             start_msf.frame = s->cur_tot_frame;
  2919.             end_msf.min = s->trkinfo[i+1].min;
  2920.             end_msf.sec = s->trkinfo[i+1].sec;
  2921.             end_msf.frame = s->trkinfo[i+1].frame;
  2922.  
  2923.             if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  2924.                       s->cur_tot_addr,
  2925.                       s->trkinfo[i+1].addr,
  2926.                       &start_msf, &end_msf, 0, 0)) {
  2927.                 cd_beep();
  2928.                 return;
  2929.             }
  2930.         }
  2931.         else {
  2932.             start_msf.min = s->cur_tot_min;
  2933.             start_msf.sec = s->cur_tot_sec;
  2934.             start_msf.frame = s->cur_tot_frame;
  2935.             end_msf.min = s->tot_min;
  2936.             end_msf.sec = s->tot_sec;
  2937.             end_msf.frame = s->tot_frame;
  2938.  
  2939.             if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  2940.                       s->cur_tot_addr, s->tot_addr,
  2941.                       &start_msf, &end_msf, 0, 0)) {
  2942.                 cd_beep();
  2943.                 return;
  2944.             }
  2945.         }
  2946.         s->mode = M_PLAY;
  2947.         dpy_playmode(s, FALSE);
  2948.         break;
  2949.  
  2950.     default:
  2951.         cd_beep();
  2952.         break;
  2953.     }
  2954. }
  2955.  
  2956.  
  2957. /*
  2958.  * scsipt_stop
  2959.  *    Stop function
  2960.  *
  2961.  * Args:
  2962.  *    s - Pointer to the curstat_t structure
  2963.  *    stop_disc - Whether to actually spin down the disc or just
  2964.  *        update status.
  2965.  *
  2966.  * Return:
  2967.  *    Nothing.
  2968.  */
  2969. void
  2970. scsipt_stop(curstat_t *s, bool_t stop_disc)
  2971. {
  2972.     /* The stop_disc parameter will cause the disc to spin down.
  2973.      * This is usually set to TRUE, but can be FALSE if the caller
  2974.      * just wants to set the current state to stop but will
  2975.      * immediately go into play state again.  Not spinning down
  2976.      * the drive makes things a little faster...
  2977.      */
  2978.  
  2979.     if (!scsipt_disc_ready(s)) {
  2980.         cd_beep();
  2981.         return;
  2982.     }
  2983.  
  2984.     switch (s->mode) {
  2985.     case M_PLAY:
  2986.     case M_PAUSE:
  2987.     case M_A:
  2988.     case M_AB:
  2989.     case M_SAMPLE:
  2990.     case M_STOP:
  2991.         /* Currently playing or paused: stop */
  2992.  
  2993.         if (stop_disc && !scsipt_do_start_stop(FALSE, FALSE)) {
  2994.             cd_beep();
  2995.             return;
  2996.         }
  2997.         scsipt_stop_stat_poll();
  2998.  
  2999.         reset_curstat(s, FALSE);
  3000.         s->mode = M_STOP;
  3001.  
  3002.         dpy_all(s);
  3003.         break;
  3004.  
  3005.     default:
  3006.         cd_beep();
  3007.         break;
  3008.     }
  3009. }
  3010.  
  3011.  
  3012. /*
  3013.  * scsipt_prevtrk
  3014.  *    Previous track function
  3015.  *
  3016.  * Args:
  3017.  *    s - Pointer to the curstat_t structure
  3018.  *
  3019.  * Return:
  3020.  *    Nothing.
  3021.  */
  3022. void
  3023. scsipt_prevtrk(curstat_t *s)
  3024. {
  3025.     sword32_t    i;
  3026.     word32_t    start_addr;
  3027.     msf_t        start_msf,
  3028.             end_msf;
  3029.     bool_t        go_prev;
  3030.  
  3031.     if (!scsipt_disc_ready(s)) {
  3032.         cd_beep();
  3033.         return;
  3034.     }
  3035.  
  3036.     switch (s->mode) {
  3037.     case M_A:
  3038.     case M_AB:
  3039.     case M_SAMPLE:
  3040.         s->mode = M_PLAY;
  3041.         dpy_playmode(s, FALSE);
  3042.         /*FALLTHROUGH*/
  3043.     case M_PLAY:
  3044.     case M_PAUSE:
  3045.         /* Find appropriate track to start */
  3046.         if (s->prog_tot > 0) {
  3047.             if (s->prog_cnt > 0) {
  3048.                 s->prog_cnt--;
  3049.                 scsipt_new_progshuf = FALSE;
  3050.             }
  3051.             i = curprog_pos(s);
  3052.         }
  3053.         else
  3054.             i = curtrk_pos(s);
  3055.  
  3056.         if (i < 0)
  3057.             return;
  3058.  
  3059.         start_addr = s->trkinfo[i].addr;
  3060.         start_msf.min = s->trkinfo[i].min;
  3061.         start_msf.sec = s->trkinfo[i].sec;
  3062.         start_msf.frame = s->trkinfo[i].frame;
  3063.         s->cur_trk = s->trkinfo[i].trkno;
  3064.         s->cur_idx = 1;
  3065.  
  3066.         /* If the current track has been playing for less
  3067.          * than app_data.prev_threshold blocks, then go
  3068.          * to the beginning of the previous track (if we
  3069.          * are not already on the first track).
  3070.          */
  3071.         go_prev = FALSE;
  3072.         if ((s->cur_tot_addr - start_addr) < app_data.prev_threshold)
  3073.             go_prev = TRUE;
  3074.  
  3075.         if (go_prev) {
  3076.             if (s->prog_tot > 0) {
  3077.                 if (s->prog_cnt > 0) {
  3078.                     s->prog_cnt--;
  3079.                     scsipt_new_progshuf = FALSE;
  3080.                 }
  3081.                 if ((i = curprog_pos(s)) < 0)
  3082.                     return;
  3083.  
  3084.                 start_addr = s->trkinfo[i].addr;
  3085.                 start_msf.min = s->trkinfo[i].min;
  3086.                 start_msf.sec = s->trkinfo[i].sec;
  3087.                 start_msf.frame = s->trkinfo[i].frame;
  3088.                 s->cur_trk = s->trkinfo[i].trkno;
  3089.             }
  3090.             else if (s->prog_tot <= 0 && i > 0) {
  3091.                 start_addr = s->trkinfo[i-1].addr;
  3092.                 start_msf.min = s->trkinfo[i-1].min;
  3093.                 start_msf.sec = s->trkinfo[i-1].sec;
  3094.                 start_msf.frame = s->trkinfo[i-1].frame;
  3095.                 s->cur_trk = s->trkinfo[i-1].trkno;
  3096.             }
  3097.         }
  3098.  
  3099.         if (s->mode == M_PAUSE)
  3100.             /* Mute: so we don't get a transient */
  3101.             scsipt_mute_on(s);
  3102.  
  3103.         if (s->prog_tot > 0) {
  3104.             /* Program/Shuffle mode: just stop the playback
  3105.              * and let scsipt_run_prog go to the previous track
  3106.              */
  3107.             scsipt_fake_stop = TRUE;
  3108.  
  3109.             /* Force status update */
  3110.             scsipt_get_playstatus(s);
  3111.         }
  3112.         else {
  3113.             end_msf.min = s->tot_min;
  3114.             end_msf.sec = s->tot_sec;
  3115.             end_msf.frame = s->tot_frame;
  3116.  
  3117.             s->cur_tot_addr = start_addr;
  3118.             s->cur_tot_min = start_msf.min;
  3119.             s->cur_tot_sec = start_msf.sec;
  3120.             s->cur_tot_frame = start_msf.frame;
  3121.             s->cur_trk_addr = 0;
  3122.             s->cur_trk_min = s->cur_trk_sec = s->cur_trk_frame = 0;
  3123.  
  3124.             dpy_track(s);
  3125.             dpy_index(s);
  3126.             dpy_time(s, FALSE);
  3127.  
  3128.             if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  3129.                       start_addr, s->tot_addr,
  3130.                       &start_msf, &end_msf, 0, 0)) {
  3131.                 cd_beep();
  3132.  
  3133.                 /* Restore volume */
  3134.                 scsipt_mute_off(s);
  3135.                 return;
  3136.             }
  3137.  
  3138.             if (s->mode == M_PAUSE) {
  3139.                 scsipt_do_pause_resume(FALSE);
  3140.  
  3141.                 /* Restore volume */
  3142.                 scsipt_mute_off(s);
  3143.             }
  3144.         }
  3145.  
  3146.         break;
  3147.  
  3148.     case M_STOP:
  3149.         if (s->prog_tot > 0) {
  3150.             /* Pre-selecting tracks not supported in shuffle
  3151.              * or program mode.
  3152.              */
  3153.             cd_beep();
  3154.             return;
  3155.         }
  3156.  
  3157.         /* Find previous track */
  3158.         if (s->cur_trk <= 0) {
  3159.             s->cur_trk = s->trkinfo[0].trkno;
  3160.             dpy_track(s);
  3161.         }
  3162.         else {
  3163.             i = curtrk_pos(s);
  3164.  
  3165.             if (i > 0) {
  3166.                 s->cur_trk = s->trkinfo[i-1].trkno;
  3167.                 dpy_track(s);
  3168.             }
  3169.         }
  3170.         break;
  3171.  
  3172.     default:
  3173.         cd_beep();
  3174.         break;
  3175.     }
  3176. }
  3177.  
  3178.  
  3179. /*
  3180.  * scsipt_nexttrk
  3181.  *    Next track function
  3182.  *
  3183.  * Args:
  3184.  *    s - Pointer to the curstat_t structure
  3185.  *
  3186.  * Return:
  3187.  *    Nothing.
  3188.  */
  3189. void
  3190. scsipt_nexttrk(curstat_t *s)
  3191. {
  3192.     sword32_t    i;
  3193.     word32_t    start_addr;
  3194.     msf_t        start_msf,
  3195.             end_msf;
  3196.  
  3197.     if (!scsipt_disc_ready(s)) {
  3198.         cd_beep();
  3199.         return;
  3200.     }
  3201.  
  3202.     switch (s->mode) {
  3203.     case M_A:
  3204.     case M_AB:
  3205.     case M_SAMPLE:
  3206.         s->mode = M_PLAY;
  3207.         dpy_playmode(s, FALSE);
  3208.         /*FALLTHROUGH*/
  3209.     case M_PLAY:
  3210.     case M_PAUSE:
  3211.         if (s->prog_tot > 0) {
  3212.             if (s->prog_cnt >= s->prog_tot) {
  3213.                 /* Disallow advancing beyond current
  3214.                  * shuffle/program sequence if
  3215.                  * repeat mode is not on.
  3216.                  */
  3217.                 if (s->repeat)
  3218.                     scsipt_new_progshuf = TRUE;
  3219.                 else
  3220.                     return;
  3221.             }
  3222.  
  3223.             if (s->mode == M_PAUSE)
  3224.                 /* Mute: so we don't get a transient */
  3225.                 scsipt_mute_on(s);
  3226.  
  3227.             /* Program/Shuffle mode: just stop the playback
  3228.              * and let scsipt_run_prog go to the next track.
  3229.              */
  3230.             scsipt_fake_stop = TRUE;
  3231.  
  3232.             /* Force status update */
  3233.             scsipt_get_playstatus(s);
  3234.  
  3235.             return;
  3236.         }
  3237.  
  3238.         /* Find next track */
  3239.         if ((i = curtrk_pos(s)) < 0)
  3240.             return;
  3241.  
  3242.         if (i < (MAXTRACK - 1) &&
  3243.             s->trkinfo[i+1].trkno >= 0 &&
  3244.             s->trkinfo[i+1].trkno != LEAD_OUT_TRACK) {
  3245.  
  3246.             start_addr = s->trkinfo[i+1].addr;
  3247.             start_msf.min = s->trkinfo[i+1].min;
  3248.             start_msf.sec = s->trkinfo[i+1].sec;
  3249.             start_msf.frame = s->trkinfo[i+1].frame;
  3250.             s->cur_trk = s->trkinfo[i+1].trkno;
  3251.             s->cur_idx = 1;
  3252.  
  3253.             if (s->mode == M_PAUSE)
  3254.                 /* Mute: so we don't get a transient */
  3255.                 scsipt_mute_on(s);
  3256.  
  3257.             end_msf.min = s->tot_min;
  3258.             end_msf.sec = s->tot_sec;
  3259.             end_msf.frame = s->tot_frame;
  3260.  
  3261.             s->cur_tot_addr = start_addr;
  3262.             s->cur_tot_min = start_msf.min;
  3263.             s->cur_tot_sec = start_msf.sec;
  3264.             s->cur_tot_frame = start_msf.frame;
  3265.             s->cur_trk_addr = 0;
  3266.             s->cur_trk_min = s->cur_trk_sec = s->cur_trk_frame = 0;
  3267.  
  3268.             dpy_track(s);
  3269.             dpy_index(s);
  3270.             dpy_time(s, FALSE);
  3271.  
  3272.             if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  3273.                       start_addr, s->tot_addr,
  3274.                       &start_msf, &end_msf, 0, 0)) {
  3275.                 cd_beep();
  3276.                 return;
  3277.             }
  3278.  
  3279.             if (s->mode == M_PAUSE) {
  3280.                 scsipt_do_pause_resume(FALSE);
  3281.  
  3282.                 /* Restore volume */
  3283.                 scsipt_mute_off(s);
  3284.             }
  3285.         }
  3286.  
  3287.         break;
  3288.  
  3289.     case M_STOP:
  3290.         if (s->prog_tot > 0) {
  3291.             /* Pre-selecting tracks not supported in shuffle
  3292.              * or program mode.
  3293.              */
  3294.             cd_beep();
  3295.             return;
  3296.         }
  3297.  
  3298.         /* Find next track */
  3299.         if (s->cur_trk <= 0) {
  3300.             s->cur_trk = s->trkinfo[0].trkno;
  3301.             dpy_track(s);
  3302.         }
  3303.         else {
  3304.             i = curtrk_pos(s);
  3305.  
  3306.             if (i >= 0 &&
  3307.                 s->trkinfo[i+1].trkno != LEAD_OUT_TRACK) {
  3308.                 s->cur_trk = s->trkinfo[i+1].trkno;
  3309.                 dpy_track(s);
  3310.             }
  3311.         }
  3312.         break;
  3313.  
  3314.     default:
  3315.         cd_beep();
  3316.         break;
  3317.     }
  3318. }
  3319.  
  3320.  
  3321. /*
  3322.  * scsipt_previdx
  3323.  *    Previous index function
  3324.  *
  3325.  * Args:
  3326.  *    s - Pointer to the curstat_t structure
  3327.  *
  3328.  * Return:
  3329.  *    Nothing.
  3330.  */
  3331. void
  3332. scsipt_previdx(curstat_t *s)
  3333. {
  3334.     msf_t        start_msf,
  3335.             end_msf;
  3336.     byte_t        idx;
  3337.  
  3338.     if (s->prog_tot > 0) {
  3339.         /* Index search is not supported in program/shuffle mode */
  3340.         cd_beep();
  3341.         return;
  3342.     }
  3343.  
  3344.     switch (s->mode) {
  3345.     case M_A:
  3346.     case M_AB:
  3347.     case M_SAMPLE:
  3348.         s->mode = M_PLAY;
  3349.         dpy_playmode(s, FALSE);
  3350.         /*FALLTHROUGH*/
  3351.     case M_PLAY:
  3352.     case M_PAUSE:
  3353.         /* Find appropriate index to start */
  3354.         if (s->cur_idx > 1 &&
  3355.             (s->cur_tot_addr - s->sav_iaddr) < app_data.prev_threshold)
  3356.             idx = s->cur_idx - 1;
  3357.         else
  3358.             idx = s->cur_idx;
  3359.         
  3360.         /* This is a Hack...
  3361.          * Since there is no standard SCSI-2 command to start
  3362.          * playback on an index boundary and then go on playing
  3363.          * until the end of the disc, we will use the PLAY AUDIO
  3364.          * TRACK/INDEX command to go to where we want to start,
  3365.          * immediately followed by a PAUSE.  We then find the
  3366.          * current block position and issue a PLAY AUDIO MSF
  3367.          * or PLAY AUDIO(12) command to start play there.
  3368.          * We mute the audio in between these operations to
  3369.          * prevent unpleasant transients.
  3370.          */
  3371.  
  3372.         /* Mute */
  3373.         scsipt_mute_on(s);
  3374.  
  3375.         if (!scsipt_do_playaudio(ADDR_TRKIDX, 0, 0, NULL, NULL,
  3376.                   (byte_t) s->cur_trk, idx)) {
  3377.             /* Restore volume */
  3378.             scsipt_mute_off(s);
  3379.             cd_beep();
  3380.             return;
  3381.         }
  3382.  
  3383.         scsipt_idx_pause = TRUE;
  3384.  
  3385.         if (!scsipt_do_pause_resume(FALSE)) {
  3386.             /* Restore volume */
  3387.             scsipt_mute_off(s);
  3388.             scsipt_idx_pause = FALSE;
  3389.             return;
  3390.         }
  3391.  
  3392.         /* Use scsipt_get_playstatus to update the current status */
  3393.         if (!scsipt_get_playstatus(s)) {
  3394.             /* Restore volume */
  3395.             scsipt_mute_off(s);
  3396.             scsipt_idx_pause = FALSE;
  3397.             return;
  3398.         }
  3399.  
  3400.         /* Save starting block addr of this index */
  3401.         s->sav_iaddr = s->cur_tot_addr;
  3402.  
  3403.         if (s->mode != M_PAUSE)
  3404.             /* Restore volume */
  3405.             scsipt_mute_off(s);
  3406.  
  3407.         start_msf.min = s->cur_tot_min;
  3408.         start_msf.sec = s->cur_tot_sec;
  3409.         start_msf.frame = s->cur_tot_frame;
  3410.         end_msf.min = s->tot_min;
  3411.         end_msf.sec = s->tot_sec;
  3412.         end_msf.frame = s->tot_frame;
  3413.  
  3414.         if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  3415.                   s->cur_tot_addr, s->tot_addr,
  3416.                   &start_msf, &end_msf, 0, 0)) {
  3417.             cd_beep();
  3418.             scsipt_idx_pause = FALSE;
  3419.             return;
  3420.         }
  3421.  
  3422.         scsipt_idx_pause = FALSE;
  3423.  
  3424.         if (s->mode == M_PAUSE) {
  3425.             scsipt_do_pause_resume(FALSE);
  3426.  
  3427.             /* Restore volume */
  3428.             scsipt_mute_off(s);
  3429.  
  3430.             /* Force update of curstat */
  3431.             scsipt_get_playstatus(s);
  3432.         }
  3433.  
  3434.         break;
  3435.  
  3436.     default:
  3437.         cd_beep();
  3438.         break;
  3439.     }
  3440. }
  3441.  
  3442.  
  3443. /*
  3444.  * scsipt_nextidx
  3445.  *    Next index function
  3446.  *
  3447.  * Args:
  3448.  *    s - Pointer to the curstat_t structure
  3449.  *
  3450.  * Return:
  3451.  *    Nothing.
  3452.  */
  3453. void
  3454. scsipt_nextidx(curstat_t *s)
  3455. {
  3456.     msf_t        start_msf,
  3457.             end_msf;
  3458.  
  3459.     if (s->prog_tot > 0) {
  3460.         /* Index search is not supported in program/shuffle mode */
  3461.         cd_beep();
  3462.         return;
  3463.     }
  3464.  
  3465.     switch (s->mode) {
  3466.     case M_A:
  3467.     case M_AB:
  3468.     case M_SAMPLE:
  3469.         s->mode = M_PLAY;
  3470.         dpy_playmode(s, FALSE);
  3471.         /*FALLTHROUGH*/
  3472.     case M_PLAY:
  3473.     case M_PAUSE:
  3474.         /* Find appropriate index to start */
  3475.         
  3476.         /* This is a Hack...
  3477.          * Since there is no standard SCSI-2 command to start
  3478.          * playback on an index boundary and then go on playing
  3479.          * until the end of the disc, we will use the PLAY AUDIO
  3480.          * TRACK/INDEX command to go to where we want to start,
  3481.          * immediately followed by a PAUSE.  We then find the
  3482.          * current block position and issue a PLAY AUDIO MSF
  3483.          * or PLAY AUDIO(12) command to start play there.
  3484.          * We mute the audio in between these operations to
  3485.          * prevent unpleasant transients.
  3486.          */
  3487.  
  3488.         /* Mute */
  3489.         scsipt_mute_on(s);
  3490.  
  3491.         if (!scsipt_do_playaudio(ADDR_TRKIDX, 0, 0, NULL, NULL,
  3492.                   (byte_t) s->cur_trk,
  3493.                   (byte_t) (s->cur_idx + 1))) {
  3494.             /* Restore volume */
  3495.             scsipt_mute_off(s);
  3496.             cd_beep();
  3497.             return;
  3498.         }
  3499.  
  3500.         scsipt_idx_pause = TRUE;
  3501.  
  3502.         if (!scsipt_do_pause_resume(FALSE)) {
  3503.             /* Restore volume */
  3504.             scsipt_mute_off(s);
  3505.             scsipt_idx_pause = FALSE;
  3506.             return;
  3507.         }
  3508.  
  3509.         /* Use scsipt_get_playstatus to update the current status */
  3510.         if (!scsipt_get_playstatus(s)) {
  3511.             /* Restore volume */
  3512.             scsipt_mute_off(s);
  3513.             scsipt_idx_pause = FALSE;
  3514.             return;
  3515.         }
  3516.  
  3517.         /* Save starting block addr of this index */
  3518.         s->sav_iaddr = s->cur_tot_addr;
  3519.  
  3520.         if (s->mode != M_PAUSE)
  3521.             /* Restore volume */
  3522.             scsipt_mute_off(s);
  3523.  
  3524.         start_msf.min = s->cur_tot_min;
  3525.         start_msf.sec = s->cur_tot_sec;
  3526.         start_msf.frame = s->cur_tot_frame;
  3527.         end_msf.min = s->tot_min;
  3528.         end_msf.sec = s->tot_sec;
  3529.         end_msf.frame = s->tot_frame;
  3530.  
  3531.         if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  3532.                   s->cur_tot_addr, s->tot_addr,
  3533.                   &start_msf, &end_msf, 0, 0)) {
  3534.             cd_beep();
  3535.             scsipt_idx_pause = FALSE;
  3536.             return;
  3537.         }
  3538.  
  3539.         scsipt_idx_pause = FALSE;
  3540.  
  3541.         if (s->mode == M_PAUSE) {
  3542.             scsipt_do_pause_resume(FALSE);
  3543.  
  3544.             /* Restore volume */
  3545.             scsipt_mute_off(s);
  3546.  
  3547.             /* Force update of curstat */
  3548.             scsipt_get_playstatus(s);
  3549.         }
  3550.  
  3551.         break;
  3552.  
  3553.     default:
  3554.         cd_beep();
  3555.         break;
  3556.     }
  3557. }
  3558.  
  3559.  
  3560. /*
  3561.  * scsipt_rew
  3562.  *    Search-rewind function
  3563.  *
  3564.  * Args:
  3565.  *    s - Pointer to the curstat_t structure
  3566.  *
  3567.  * Return:
  3568.  *    Nothing.
  3569.  */
  3570. void
  3571. scsipt_rew(curstat_t *s, bool_t start)
  3572. {
  3573.     sword32_t    i;
  3574.     msf_t        start_msf,
  3575.             end_msf;
  3576.     byte_t        vol;
  3577.  
  3578.     switch (s->mode) {
  3579.     case M_A:
  3580.     case M_AB:
  3581.     case M_SAMPLE:
  3582.         /* Go to normal play mode first */
  3583.         scsipt_play_pause(s);
  3584.  
  3585.         /*FALLTHROUGH*/
  3586.     case M_PLAY:
  3587.     case M_PAUSE:
  3588.         if (start) {
  3589.             /* Button press */
  3590.  
  3591.             if (s->mode == M_PLAY)
  3592.                 scsipt_stop_stat_poll();
  3593.  
  3594.             /* Reduce volume */
  3595.             vol = (byte_t) ((int) s->level *
  3596.                 app_data.skip_vol / 100);
  3597.  
  3598.             (void) scsipt_cfg_vol((int)
  3599.                 ((vol < (byte_t)app_data.skip_minvol) ?
  3600.                  (byte_t) app_data.skip_minvol : vol),
  3601.                 s,
  3602.                 FALSE,
  3603.                 0
  3604.             );
  3605.  
  3606.             /* Start search rewind */
  3607.             scsipt_start_search = TRUE;
  3608.             scsipt_run_rew(s);
  3609.         }
  3610.         else {
  3611.             /* Button release */
  3612.  
  3613.             scsipt_stop_rew(s);
  3614.  
  3615.             /* Update display */
  3616.             scsipt_get_playstatus(s);
  3617.  
  3618.             if (s->mode == M_PAUSE)
  3619.                 /* Mute: so we don't get a transient */
  3620.                 scsipt_mute_on(s);
  3621.             else
  3622.                 /* Restore volume */
  3623.                 scsipt_mute_off(s);
  3624.  
  3625.             if (s->shuffle || s->program) {
  3626.                 if ((i = curtrk_pos(s)) < 0 ||
  3627.                     s->trkinfo[i].trkno == LEAD_OUT_TRACK) {
  3628.                     /* Restore volume */
  3629.                     scsipt_mute_off(s);
  3630.                     return;
  3631.                 }
  3632.  
  3633.                 start_msf.min = s->cur_tot_min;
  3634.                 start_msf.sec = s->cur_tot_sec;
  3635.                 start_msf.frame = s->cur_tot_frame;
  3636.                 end_msf.min = s->trkinfo[i+1].min;
  3637.                 end_msf.sec = s->trkinfo[i+1].sec;
  3638.                 end_msf.frame = s->trkinfo[i+1].frame;
  3639.  
  3640.                 if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  3641.                           s->cur_tot_addr,
  3642.                           s->trkinfo[i+1].addr,
  3643.                           &start_msf, &end_msf,
  3644.                           0, 0)) {
  3645.                     cd_beep();
  3646.  
  3647.                     /* Restore volume */
  3648.                     scsipt_mute_off(s);
  3649.                     return;
  3650.                 }
  3651.             }
  3652.             else {
  3653.                 start_msf.min = s->cur_tot_min;
  3654.                 start_msf.sec = s->cur_tot_sec;
  3655.                 start_msf.frame = s->cur_tot_frame;
  3656.                 end_msf.min = s->tot_min;
  3657.                 end_msf.sec = s->tot_sec;
  3658.                 end_msf.frame = s->tot_frame;
  3659.  
  3660.                 if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  3661.                           s->cur_tot_addr,
  3662.                           s->tot_addr,
  3663.                           &start_msf, &end_msf,
  3664.                           0, 0)) {
  3665.                     cd_beep();
  3666.  
  3667.                     /* Restore volume */
  3668.                     scsipt_mute_off(s);
  3669.                     return;
  3670.                 }
  3671.             }
  3672.  
  3673.             if (s->mode == M_PAUSE) {
  3674.                 scsipt_do_pause_resume(FALSE);
  3675.  
  3676.                 /* Restore volume */
  3677.                 scsipt_mute_off(s);
  3678.             }
  3679.             else
  3680.                 scsipt_start_stat_poll(s);
  3681.         }
  3682.         break;
  3683.  
  3684.     default:
  3685.         if (start)
  3686.             cd_beep();
  3687.         break;
  3688.     }
  3689. }
  3690.  
  3691.  
  3692. /*
  3693.  * scsipt_ff
  3694.  *    Search-fast-forward function
  3695.  *
  3696.  * Args:
  3697.  *    s - Pointer to the curstat_t structure
  3698.  *
  3699.  * Return:
  3700.  *    Nothing.
  3701.  */
  3702. void
  3703. scsipt_ff(curstat_t *s, bool_t start)
  3704. {
  3705.     sword32_t    i;
  3706.     msf_t        start_msf,
  3707.             end_msf;
  3708.     byte_t        vol;
  3709.  
  3710.     switch (s->mode) {
  3711.     case M_A:
  3712.     case M_AB:
  3713.     case M_SAMPLE:
  3714.         /* Go to normal play mode first */
  3715.         scsipt_play_pause(s);
  3716.  
  3717.         /*FALLTHROUGH*/
  3718.     case M_PLAY:
  3719.     case M_PAUSE:
  3720.         if (start) {
  3721.             /* Button press */
  3722.  
  3723.             if (s->mode == M_PLAY)
  3724.                 scsipt_stop_stat_poll();
  3725.  
  3726.             /* Reduce volume */
  3727.             vol = (byte_t) ((int) s->level *
  3728.                 app_data.skip_vol / 100);
  3729.  
  3730.             (void) scsipt_cfg_vol((int)
  3731.                 ((vol < (byte_t)app_data.skip_minvol) ?
  3732.                  (byte_t) app_data.skip_minvol : vol),
  3733.                 s,
  3734.                 FALSE,
  3735.                 0
  3736.             );
  3737.  
  3738.             /* Start search forward */
  3739.             scsipt_start_search = TRUE;
  3740.             scsipt_run_ff(s);
  3741.         }
  3742.         else {
  3743.             /* Button release */
  3744.  
  3745.             scsipt_stop_ff(s);
  3746.  
  3747.             /* Update display */
  3748.             scsipt_get_playstatus(s);
  3749.  
  3750.             if (s->mode == M_PAUSE)
  3751.                 /* Mute: so we don't get a transient */
  3752.                 scsipt_mute_on(s);
  3753.             else
  3754.                 /* Restore volume */
  3755.                 scsipt_mute_off(s);
  3756.  
  3757.             if (s->shuffle || s->program) {
  3758.                 if ((i = curtrk_pos(s)) < 0 ||
  3759.                     s->trkinfo[i].trkno == LEAD_OUT_TRACK) {
  3760.                     /* Restore volume */
  3761.                     scsipt_mute_off(s);
  3762.                     return;
  3763.                 }
  3764.  
  3765.                 start_msf.min = s->cur_tot_min;
  3766.                 start_msf.sec = s->cur_tot_sec;
  3767.                 start_msf.frame = s->cur_tot_frame;
  3768.                 end_msf.min = s->trkinfo[i+1].min;
  3769.                 end_msf.sec = s->trkinfo[i+1].sec;
  3770.                 end_msf.frame = s->trkinfo[i+1].frame;
  3771.  
  3772.                 if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  3773.                           s->cur_tot_addr,
  3774.                           s->trkinfo[i+1].addr,
  3775.                           &start_msf, &end_msf,
  3776.                           0, 0)) {
  3777.                     cd_beep();
  3778.  
  3779.                     /* Restore volume */
  3780.                     scsipt_mute_off(s);
  3781.                     return;
  3782.                 }
  3783.             }
  3784.             else {
  3785.                 start_msf.min = s->cur_tot_min;
  3786.                 start_msf.sec = s->cur_tot_sec;
  3787.                 start_msf.frame = s->cur_tot_frame;
  3788.                 end_msf.min = s->tot_min;
  3789.                 end_msf.sec = s->tot_sec;
  3790.                 end_msf.frame = s->tot_frame;
  3791.  
  3792.                 if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  3793.                           s->cur_tot_addr,
  3794.                           s->tot_addr,
  3795.                           &start_msf, &end_msf,
  3796.                           0, 0)) {
  3797.                     cd_beep();
  3798.  
  3799.                     /* Restore volume */
  3800.                     scsipt_mute_off(s);
  3801.                     return;
  3802.                 }
  3803.             }
  3804.             if (s->mode == M_PAUSE) {
  3805.                 scsipt_do_pause_resume(FALSE);
  3806.  
  3807.                 /* Restore volume */
  3808.                 scsipt_mute_off(s);
  3809.             }
  3810.             else
  3811.                 scsipt_start_stat_poll(s);
  3812.         }
  3813.         break;
  3814.  
  3815.     default:
  3816.         if (start)
  3817.             cd_beep();
  3818.         break;
  3819.     }
  3820. }
  3821.  
  3822.  
  3823. /*
  3824.  * scsipt_warp
  3825.  *    Track warp function
  3826.  *
  3827.  * Args:
  3828.  *    s - Pointer to the curstat_t structure
  3829.  *
  3830.  * Return:
  3831.  *    Nothing.
  3832.  */
  3833. void
  3834. scsipt_warp(curstat_t *s)
  3835. {
  3836.     word32_t    start_addr,
  3837.             end_addr;
  3838.     msf_t        start_msf,
  3839.             end_msf;
  3840.     int        i;
  3841.  
  3842.     start_addr = s->cur_tot_addr;
  3843.     start_msf.min = s->cur_tot_min;
  3844.     start_msf.sec = s->cur_tot_sec;
  3845.     start_msf.frame = s->cur_tot_frame;
  3846.  
  3847.     switch (s->mode) {
  3848.     case M_A:
  3849.     case M_AB:
  3850.     case M_SAMPLE:
  3851.         /* Go to normal play mode first */
  3852.         scsipt_play_pause(s);
  3853.  
  3854.         /*FALLTHROUGH*/
  3855.     case M_PLAY:
  3856.     case M_PAUSE:
  3857.         if (s->shuffle || s->program) {
  3858.             if ((i = curtrk_pos(s)) < 0) {
  3859.                 cd_beep();
  3860.                 return;
  3861.             }
  3862.  
  3863.             end_addr = s->trkinfo[i+1].addr;
  3864.             end_msf.min = s->trkinfo[i+1].min;
  3865.             end_msf.sec = s->trkinfo[i+1].sec;
  3866.             end_msf.frame = s->trkinfo[i+1].frame;
  3867.         }
  3868.         else {
  3869.             end_addr = s->tot_addr;
  3870.             end_msf.min = s->tot_min;
  3871.             end_msf.sec = s->tot_sec;
  3872.             end_msf.frame = s->tot_frame;
  3873.         }
  3874.  
  3875.         if (s->mode == M_PAUSE)
  3876.             /* Mute: so we don't get a transient */
  3877.             scsipt_mute_on(s);
  3878.  
  3879.         if (!scsipt_do_playaudio(ADDR_BLK | ADDR_MSF,
  3880.                   start_addr, end_addr,
  3881.                   &start_msf, &end_msf,
  3882.                   0, 0)) {
  3883.             cd_beep();
  3884.  
  3885.             /* Restore volume */
  3886.             scsipt_mute_off(s);
  3887.             return;
  3888.         }
  3889.  
  3890.         if (s->mode == M_PAUSE) {
  3891.             scsipt_do_pause_resume(FALSE);
  3892.  
  3893.             /* Restore volume */
  3894.             scsipt_mute_off(s);
  3895.         }
  3896.  
  3897.         break;
  3898.  
  3899.     default:
  3900.         break;
  3901.     }
  3902. }
  3903.  
  3904.  
  3905. /*
  3906.  * scsipt_route
  3907.  *    Channel routing function
  3908.  *
  3909.  * Args:
  3910.  *    s - Pointer to the curstat_t structure
  3911.  *
  3912.  * Return:
  3913.  *    Nothing.
  3914.  */
  3915. void
  3916. scsipt_route(curstat_t *s)
  3917. {
  3918.     byte_t    val0,
  3919.         val1;
  3920.     bool_t    ret;
  3921.  
  3922.     if (!app_data.chroute_supp)
  3923.         return;
  3924.  
  3925.     if (scsipt_vutbl[app_data.vendor_code].route != NULL) {
  3926.         (void) scsipt_vutbl[app_data.vendor_code].route(s);
  3927.         return;
  3928.     }
  3929.  
  3930.     val0 = scsipt_route_val(app_data.ch_route, 0);
  3931.     val1 = scsipt_route_val(app_data.ch_route, 1);
  3932.  
  3933.     if (val0 == scsipt_route_left && val1 == scsipt_route_right)
  3934.         /* No change: just return */
  3935.         return;
  3936.  
  3937.     scsipt_route_left = val0;
  3938.     scsipt_route_right = val1;
  3939.  
  3940.     /* With SCSI-2, channel routing is done with the volume control */
  3941.     (void) scsipt_cfg_vol(s->level, s, FALSE, 0);
  3942. }
  3943.  
  3944.  
  3945. /*
  3946.  * scsipt_mute_on
  3947.  *    Mute audio function
  3948.  *
  3949.  * Args:
  3950.  *    s - Pointer to the curstat_t structure
  3951.  *
  3952.  * Return:
  3953.  *    Nothing.
  3954.  */
  3955. void
  3956. scsipt_mute_on(curstat_t *s)
  3957. {
  3958.     (void) scsipt_cfg_vol(0, s, FALSE, 0);
  3959. }
  3960.  
  3961.  
  3962. /*
  3963.  * scsipt_mute_off
  3964.  *    Un-mute audio function
  3965.  *
  3966.  * Args:
  3967.  *    s - Pointer to the curstat_t structure
  3968.  *
  3969.  * Return:
  3970.  *    Nothing.
  3971.  */
  3972. void
  3973. scsipt_mute_off(curstat_t *s)
  3974. {
  3975.     (void) scsipt_cfg_vol((int) s->level, s, FALSE, 0);
  3976. }
  3977.  
  3978.  
  3979. /*
  3980.  * scsipt_start
  3981.  *    Start the SCSI pass-through module.
  3982.  *
  3983.  * Args:
  3984.  *    s - Pointer to the curstat_t structure
  3985.  *
  3986.  * Return:
  3987.  *    Nothing.
  3988.  */
  3989. void
  3990. scsipt_start(curstat_t *s)
  3991. {
  3992.     /* Check to see if disc is ready */
  3993.     (void) scsipt_disc_ready(s);
  3994.  
  3995.     /* Update display */
  3996.     dpy_all(s);
  3997. }
  3998.  
  3999.  
  4000. /*
  4001.  * scsipt_icon
  4002.  *    Handler for main window iconification/de-iconification
  4003.  *
  4004.  * Args:
  4005.  *    s - Pointer to the curstat_t structure
  4006.  *    iconified - Whether the main window is iconified
  4007.  *
  4008.  * Return:
  4009.  *    Nothing.
  4010.  */
  4011. void
  4012. scsipt_icon(curstat_t *s, bool_t iconified)
  4013. {
  4014.     /* This function attempts to reduce the status polling frequency
  4015.      * when possible to cut down on CPU and SCSI bus usage.  This is
  4016.      * done when the CD player is iconified.
  4017.      */
  4018.  
  4019.     /* Increase status polling interval by 4 seconds when iconified */
  4020.     if (iconified)
  4021.         scsipt_stat_interval = app_data.stat_interval + 4000;
  4022.     else
  4023.         scsipt_stat_interval = app_data.stat_interval;
  4024.  
  4025.     /* Check disc status */
  4026.     if (!scsipt_disc_ready(s))
  4027.         return;
  4028.  
  4029.     switch (s->mode) {
  4030.     case M_STOP:
  4031.     case M_NODISC:
  4032.     case M_PAUSE:
  4033.         break;
  4034.  
  4035.     case M_A:
  4036.     case M_AB:
  4037.     case M_SAMPLE:
  4038.         /* No optimization in these modes */
  4039.         scsipt_stat_interval = app_data.stat_interval;
  4040.         break;
  4041.  
  4042.     case M_PLAY:
  4043.         if (!iconified) {
  4044.             /* Force an immediate update */
  4045.             scsipt_stop_stat_poll();
  4046.             scsipt_start_stat_poll(s);
  4047.         }
  4048.         break;
  4049.     }
  4050. }
  4051.  
  4052.  
  4053. /*
  4054.  * scsipt_halt
  4055.  *    Shut down the SCSI pass-through and vendor-unique modules.
  4056.  *
  4057.  * Args:
  4058.  *    s - Pointer to the curstat_t structure
  4059.  *
  4060.  * Return:
  4061.  *    Nothing.
  4062.  */
  4063. void
  4064. scsipt_halt(curstat_t *s)
  4065. {
  4066.     int    i;
  4067.  
  4068.     /* Re-enable front-panel eject button */
  4069.     if (s->caddy_lock)
  4070.         scsipt_lock(s, FALSE);
  4071.  
  4072.     if (s->mode != M_NODISC) {
  4073.         if (app_data.exit_eject && app_data.eject_supp) {
  4074.             /* User closing application: Eject disc */
  4075.             scsipt_do_start_stop(FALSE, TRUE);
  4076.         }
  4077.         else {
  4078.             if (app_data.exit_stop)
  4079.                 /* User closing application: Stop disc */
  4080.                 scsipt_do_start_stop(FALSE, FALSE);
  4081.  
  4082.             switch (s->mode) {
  4083.             case M_PLAY:
  4084.             case M_PAUSE:
  4085.             case M_A:
  4086.             case M_AB:
  4087.             case M_SAMPLE:
  4088.                 scsipt_stop_stat_poll();
  4089.                 break;
  4090.             }
  4091.         }
  4092.     }
  4093.  
  4094.     /* Shut down the vendor unique modules */
  4095.     for (i = 0; i < MAX_VENDORS; i++) {
  4096.         if (scsipt_vutbl[i].halt != NULL)
  4097.             scsipt_vutbl[i].halt();
  4098.     }
  4099.  
  4100.     /* Close device */
  4101.     pthru_close();
  4102. }
  4103.  
  4104.  
  4105. /*
  4106.  * scsipt_mode
  4107.  *    Return a text string indicating the current SCSI mode
  4108.  *    ("SCSI-2" or a particular vendor-unique string).
  4109.  *
  4110.  * Args:
  4111.  *    Nothing.
  4112.  *
  4113.  * Return:
  4114.  *    SCSI mode text string.
  4115.  */
  4116. char *
  4117. scsipt_mode(void)
  4118. {
  4119.     static char    str[STR_BUF_SZ];
  4120.  
  4121.     sprintf(str, "%s%s", scsipt_vutbl[app_data.vendor_code].vendor,
  4122.         app_data.vendor_code == VENDOR_SCSI2 ? "" : " vendor unique");
  4123.  
  4124.     return (str);
  4125. }
  4126.  
  4127.  
  4128. /*
  4129.  * scsipt_vers
  4130.  *    Return a text string indicating the SCSI pass-through module's
  4131.  *    version number and which SCSI-1 vendor-unique modes are
  4132.  *    supported in this binary.
  4133.  *
  4134.  * Args:
  4135.  *    Nothing.
  4136.  *
  4137.  * Return:
  4138.  *    Version text string.
  4139.  */
  4140. char *
  4141. scsipt_vers(void)
  4142. {
  4143.     int        i;
  4144.     bool_t        vusupp = FALSE;
  4145.     static char    vers[256];
  4146.  
  4147.     sprintf(vers, "%s\n%s",
  4148.         "SCSI-2 Pass-through method",
  4149.         "SCSI-1 Vendor-unique support:");
  4150.  
  4151.     for (i = 0; i < MAX_VENDORS; i++) {
  4152.         if (scsipt_vutbl[i].vendor != NULL && i != VENDOR_SCSI2) {
  4153.             sprintf(vers, "%s%s%s",
  4154.                 vers,
  4155.                 vusupp ? ", " : "\n   ",
  4156.                 scsipt_vutbl[i].vendor);
  4157.             vusupp = TRUE;
  4158.         }
  4159.     }
  4160.  
  4161.     sprintf(vers, "%s%s\n%s", vers, vusupp ? "" : " none", pthru_vers());
  4162.  
  4163.     return (vers);
  4164. }
  4165.  
  4166. #endif    /* DI_SCSIPT */
  4167.  
  4168.